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

Merge branch 'bpf-support-resilient-split-btf'

Alan Maguire says:

====================
bpf: support resilient split BTF

Split BPF Type Format (BTF) provides huge advantages in that kernel
modules only have to provide type information for types that they do not
share with the core kernel; for core kernel types, split BTF refers to
core kernel BTF type ids. So for a STRUCT sk_buff, a module that
uses that structure (or a pointer to it) simply needs to refer to the
core kernel type id, saving the need to define the structure and its many
dependents. This cuts down on duplication and makes BTF as compact
as possible.

However, there is a downside. This scheme requires the references from
split BTF to base BTF to be valid not just at encoding time, but at use
time (when the module is loaded). Even a small change in kernel types
can perturb the type ids in core kernel BTF, and - if the new reproducible
BTF option is not used - pahole's parallel processing of compilation units
can lead to different type ids for the same kernel if the BTF is
regenerated.

So we have a robustness problem for split BTF for cases where a module is
not always compiled at the same time as the kernel. This problem is
particularly acute for distros which generally want module builders to be
able to compile a module for the lifetime of a Linux stable-based release,
and have it continue to be valid over the lifetime of that release, even
as changes in data structures (and hence BTF types) accrue. Today it's not
possible to generate BTF for modules that works beyond the initial
kernel it is compiled against - kernel bugfixes etc invalidate the split
BTF references to vmlinux BTF, and BTF is no longer usable for the
module.

The goal of this series is to provide options to provide additional
context for cases like this. That context comes in the form of
distilled base BTF; it stands in for the base BTF, and contains
information about the types referenced from split BTF, but not their
full descriptions. The modified split BTF will refer to type ids in
this .BTF.base section, and when the kernel loads such modules it
will use that .BTF.base to map references from split BTF to the
equivalent current vmlinux base BTF types. Once this relocation
process has succeeded, the module BTF available in /sys/kernel/btf
will look exactly as if it was built with the current vmlinux;
references to base types will be fixed up etc.

A module builder - using this series along with the pahole changes -
can then build a module with distilled base BTF via an out-of-tree
module build, i.e.

make -C . M=path/2/module

The module will have a .BTF section (the split BTF) and a
.BTF.base section. The latter is small in size - distilled base
BTF does not need full struct/union/enum information for named
types for example. For 2667 modules built with distilled base BTF,
the average size observed was 1556 bytes (stddev 1563). The overall
size added to this 2667 modules was 5.3Mb.

Note that for the in-tree modules, this approach is not needed as
split and base BTF in the case of in-tree modules are always built
and re-built together.

The series first focuses on generating split BTF with distilled base
BTF; then relocation support is added to allow split BTF with
an associated distlled base to be relocated with a new base BTF.

Next Eduard's patch allows BTF ELF parsing to work with both
.BTF and .BTF.base sections; this ensures that bpftool will be
able to dump BTF for a module with a .BTF.base section for example,
or indeed dump relocated BTF where a module and a "-B vmlinux"
is supplied.

Then we add support to resolve_btfids to ignore base BTF - i.e.
to avoid relocation - if a .BTF.base section is found. This ensures
the .BTF.ids section is populated with ids relative to the distilled
base (these will be relocated as part of module load).

Finally the series supports storage of .BTF.base data/size in modules
and supports sharing of relocation code with the kernel to allow
relocation of module BTF. For the kernel, this relocation
process happens at module load time, and we relocate split BTF
references to point at types in the current vmlinux BTF. As part of
this, .BTF.ids references need to be mapped also.

So concretely, what happens is

- we generate split BTF in the .BTF section of a module that refers to
types in the .BTF.base section as base types; the latter are not full
type descriptions but provide information about the base type. So
a STRUCT sk_buff would be represented as a FWD struct sk_buff in
distilled base BTF for example.
- when the module is loaded, the split BTF is relocated with vmlinux
BTF; in the case of the FWD struct sk_buff, we find the STRUCT sk_buff
in vmlinux BTF and map all split BTF references to the distilled base
FWD sk_buff, replacing them with references to the vmlinux BTF
STRUCT sk_buff.

A previous approach to this problem [1] utilized standalone BTF for such
cases - where the BTF is not defined relative to base BTF so there is no
relocation required. The problem with that approach is that from
the verifier perspective, some types are special, and having a custom
representation of a core kernel type that did not necessarily match the
current representation is not tenable. So the approach taken here was
to preserve the split BTF model while minimizing the representation of
the context needed to relocate split and current vmlinux BTF.

To generate distilled .BTF.base sections the associated dwarves
patch (to be applied on the "next" branch there) is needed [3]
Without it, things will still work but modules will not be built
with a .BTF.base section.

Changes since v5[4]:

- Update search of distilled types to return the first occurrence
of a string (or a string+size pair); this allows us to iterate
over all matches in distilled base BTF (Andrii, patch 3)
- Update to use BTF field iterators (Andrii, patches 1, 3 and 8)
- Update tests to cover multiple match and associated error cases
(Eduard, patch 4)
- Rename elf_sections_info to btf_elf_secs, remove use of
libbpf_get_error(), reset btf->owns_base when relocation
succeeds (Andrii, patch 5)

Changes since v4[5]:

- Moved embeddedness, duplicate name checks to relocation time
and record struct/union size for all distilled struct/unions
instead of using forwards. This allows us to carry out
type compatibility checks based on the base BTF we want to
relocate with (Eduard, patches 1, 3)
- Moved to using qsort() instead of qsort_r() as support for
qsort_r() appears to be missing in Android libc (Andrii, patch 3)
- Sorting/searching now incorporates size matching depending
on BTF kind and embeddedness of struct/union (Eduard, Andrii,
patch 3)
- Improved naming of various types during relocation to avoid
confusion (Andrii, patch 3)
- Incorporated Eduard's patch (patch 5) which handles .BTF.base
sections internally in btf_parse_elf(). This makes ELF parsing
work with split BTF, split BTF with a distilled base, split
BTF with a distilled base _and_ base BTF (by relocating) etc.
Having this avoids the need for bpftool changes; it will work
as-is with .BTF.base sections (Eduard, patch 4)
- Updated resolve_btfids to _not_ relocate BTF for modules
where a .BTF.base section is present; in that one case we
do not want to relocate BTF as the .BTF.ids section should
reflect ids in .BTF.base which will later be relocated on
module load (Eduard, Andrii, patch 5)

Changes since v3[6]:

- distill now checks for duplicate-named struct/unions and records
them as a sized struct/union to help identify which of the
multiple base BTF structs/unions it refers to (Eduard, patch 1)
- added test support for multiple name handling (Eduard, patch 2)
- simplified the string mapping when updating split BTF to use
base BTF instead of distilled base. Since the only string
references split BTF can make to base BTF are the names of
the base types, create a string map from distilled string
offset -> base BTF string offset and update string offsets
by visiting all strings in split BTF; this saves having to
do costly searches of base BTF (Eduard, patch 7,10)
- fixed bpftool manpage and indentation issues (Quentin, patch 11)

Also explored Eduard's suggestion of doing an implicit fallback
to checking for .BTF.base section in btf__parse() when it is
called to get base BTF. However while it is doable, it turned
out to be difficult operationally. Since fallback is implicit
we do not know the source of the BTF - was it from .BTF or
.BTF.base? In bpftool, we want to try first standalone BTF,
then split, then split with distilled base. Having a way
to explicitly request .BTF.base via btf__parse_opts() fits
that model better.

Changes since v2[7]:

- submitted patch to use --btf_features in Makefile.btf for pahole
v1.26 and later separately (Andrii). That has landed in bpf-next
now.
- distilled base now encodes ENUM64 as fwd ENUM (size 8), eliminating
the need for support for ENUM64 in btf__add_fwd (patch 1, Andrii)
- moved to distilling only named types, augmenting split BTF with
associated reference types; this simplifies greatly the distilled
base BTF and the mapping operation between distilled and base
BTF when relocating (most of the series changes, Andrii)
- relocation now iterates over base BTF, looking for matches based
on name in distilled BTF. Distilled BTF is pre-sorted by name
(Andrii, patch 8)
- removed most redundant compabitiliby checks aside from struct
size for base types/embedded structs and kind compatibility
(since we only match on name) (Andrii, patch 8)
- btf__parse_opts() now replaces btf_parse() internally in libbpf
(Eduard, patch 3)

Changes since RFC [8]:

- updated terminology; we replace clunky "base reference" BTF with
distilling base BTF into a .BTF.base section. Similarly BTF
reconcilation becomes BTF relocation (Andrii, most patches)
- add distilled base BTF by default for out-of-tree modules
(Alexei, patch 8)
- distill algorithm updated to record size of embedded struct/union
by recording it as a 0-vlen STRUCT/UNION with size preserved
(Andrii, patch 2)
- verify size match on relocation for such STRUCT/UNIONs (Andrii,
patch 9)
- with embedded STRUCT/UNION recording size, we can have bpftool
dump a header representation using .BTF.base + .BTF sections
rather than special-casing and refusing to use "format c" for
that case (patch 5)
- match enum with enum64 and vice versa (Andrii, patch 9)
- ensure that resolve_btfids works with BTF without .BTF.base
section (patch 7)
- update tests to cover embedded types, arrays and function
prototypes (patches 3, 12)

[1] https://lore.kernel.org/bpf/20231112124834.388735-14-alan.maguire@oracle.com/
[2] https://lore.kernel.org/bpf/20240501175035.2476830-1-alan.maguire@oracle.com/
[3] https://lore.kernel.org/bpf/20240517102714.4072080-1-alan.maguire@oracle.com/
[4] https://lore.kernel.org/bpf/20240528122408.3154936-1-alan.maguire@oracle.com/
[5] https://lore.kernel.org/bpf/20240517102246.4070184-1-alan.maguire@oracle.com/
[6] https://lore.kernel.org/bpf/20240510103052.850012-1-alan.maguire@oracle.com/
[7] https://lore.kernel.org/bpf/20240424154806.3417662-1-alan.maguire@oracle.com/
[8] https://lore.kernel.org/bpf/20240322102455.98558-1-alan.maguire@oracle.com/
====================

Link: https://lore.kernel.org/r/20240613095014.357981-1-alan.maguire@oracle.com
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>

+1558 -71
+8
tools/bpf/resolve_btfids/main.c
··· 409 409 obj->efile.idlist = data; 410 410 obj->efile.idlist_shndx = idx; 411 411 obj->efile.idlist_addr = sh.sh_addr; 412 + } else if (!strcmp(name, BTF_BASE_ELF_SEC)) { 413 + /* If a .BTF.base section is found, do not resolve 414 + * BTF ids relative to vmlinux; resolve relative 415 + * to the .BTF.base section instead. btf__parse_split() 416 + * will take care of this once the base BTF it is 417 + * passed is NULL. 418 + */ 419 + obj->base_btf_path = NULL; 412 420 } 413 421 414 422 if (compressed_section_fix(elf, scn, &sh))
+1 -1
tools/lib/bpf/Build
··· 1 1 libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o \ 2 2 netlink.o bpf_prog_linfo.o libbpf_probes.o hashmap.o \ 3 3 btf_dump.o ringbuf.o strset.o linker.o gen_loader.o relo_core.o \ 4 - usdt.o zip.o elf.o features.o 4 + usdt.o zip.o elf.o features.o btf_relocate.o
+450 -70
tools/lib/bpf/btf.c
··· 116 116 /* whether strings are already deduplicated */ 117 117 bool strs_deduped; 118 118 119 + /* whether base_btf should be freed in btf_free for this instance */ 120 + bool owns_base; 121 + 119 122 /* BTF object FD, if loaded into kernel */ 120 123 int fd; 121 124 ··· 972 969 free(btf->raw_data); 973 970 free(btf->raw_data_swapped); 974 971 free(btf->type_offs); 972 + if (btf->owns_base) 973 + btf__free(btf->base_btf); 975 974 free(btf); 976 975 } 977 976 ··· 1089 1084 return libbpf_ptr(btf_new(data, size, base_btf)); 1090 1085 } 1091 1086 1087 + struct btf_elf_secs { 1088 + Elf_Data *btf_data; 1089 + Elf_Data *btf_ext_data; 1090 + Elf_Data *btf_base_data; 1091 + }; 1092 + 1093 + static int btf_find_elf_sections(Elf *elf, const char *path, struct btf_elf_secs *secs) 1094 + { 1095 + Elf_Scn *scn = NULL; 1096 + Elf_Data *data; 1097 + GElf_Ehdr ehdr; 1098 + size_t shstrndx; 1099 + int idx = 0; 1100 + 1101 + if (!gelf_getehdr(elf, &ehdr)) { 1102 + pr_warn("failed to get EHDR from %s\n", path); 1103 + goto err; 1104 + } 1105 + 1106 + if (elf_getshdrstrndx(elf, &shstrndx)) { 1107 + pr_warn("failed to get section names section index for %s\n", 1108 + path); 1109 + goto err; 1110 + } 1111 + 1112 + if (!elf_rawdata(elf_getscn(elf, shstrndx), NULL)) { 1113 + pr_warn("failed to get e_shstrndx from %s\n", path); 1114 + goto err; 1115 + } 1116 + 1117 + while ((scn = elf_nextscn(elf, scn)) != NULL) { 1118 + Elf_Data **field; 1119 + GElf_Shdr sh; 1120 + char *name; 1121 + 1122 + idx++; 1123 + if (gelf_getshdr(scn, &sh) != &sh) { 1124 + pr_warn("failed to get section(%d) header from %s\n", 1125 + idx, path); 1126 + goto err; 1127 + } 1128 + name = elf_strptr(elf, shstrndx, sh.sh_name); 1129 + if (!name) { 1130 + pr_warn("failed to get section(%d) name from %s\n", 1131 + idx, path); 1132 + goto err; 1133 + } 1134 + 1135 + if (strcmp(name, BTF_ELF_SEC) == 0) 1136 + field = &secs->btf_data; 1137 + else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) 1138 + field = &secs->btf_ext_data; 1139 + else if (strcmp(name, BTF_BASE_ELF_SEC) == 0) 1140 + field = &secs->btf_base_data; 1141 + else 1142 + continue; 1143 + 1144 + data = elf_getdata(scn, 0); 1145 + if (!data) { 1146 + pr_warn("failed to get section(%d, %s) data from %s\n", 1147 + idx, name, path); 1148 + goto err; 1149 + } 1150 + *field = data; 1151 + } 1152 + 1153 + return 0; 1154 + 1155 + err: 1156 + return -LIBBPF_ERRNO__FORMAT; 1157 + } 1158 + 1092 1159 static struct btf *btf_parse_elf(const char *path, struct btf *base_btf, 1093 1160 struct btf_ext **btf_ext) 1094 1161 { 1095 - Elf_Data *btf_data = NULL, *btf_ext_data = NULL; 1096 - int err = 0, fd = -1, idx = 0; 1162 + struct btf_elf_secs secs = {}; 1163 + struct btf *dist_base_btf = NULL; 1097 1164 struct btf *btf = NULL; 1098 - Elf_Scn *scn = NULL; 1165 + int err = 0, fd = -1; 1099 1166 Elf *elf = NULL; 1100 - GElf_Ehdr ehdr; 1101 - size_t shstrndx; 1102 1167 1103 1168 if (elf_version(EV_CURRENT) == EV_NONE) { 1104 1169 pr_warn("failed to init libelf for %s\n", path); ··· 1182 1107 return ERR_PTR(err); 1183 1108 } 1184 1109 1185 - err = -LIBBPF_ERRNO__FORMAT; 1186 - 1187 1110 elf = elf_begin(fd, ELF_C_READ, NULL); 1188 1111 if (!elf) { 1189 1112 pr_warn("failed to open %s as ELF file\n", path); 1190 1113 goto done; 1191 1114 } 1192 - if (!gelf_getehdr(elf, &ehdr)) { 1193 - pr_warn("failed to get EHDR from %s\n", path); 1115 + 1116 + err = btf_find_elf_sections(elf, path, &secs); 1117 + if (err) 1194 1118 goto done; 1195 - } 1196 1119 1197 - if (elf_getshdrstrndx(elf, &shstrndx)) { 1198 - pr_warn("failed to get section names section index for %s\n", 1199 - path); 1200 - goto done; 1201 - } 1202 - 1203 - if (!elf_rawdata(elf_getscn(elf, shstrndx), NULL)) { 1204 - pr_warn("failed to get e_shstrndx from %s\n", path); 1205 - goto done; 1206 - } 1207 - 1208 - while ((scn = elf_nextscn(elf, scn)) != NULL) { 1209 - GElf_Shdr sh; 1210 - char *name; 1211 - 1212 - idx++; 1213 - if (gelf_getshdr(scn, &sh) != &sh) { 1214 - pr_warn("failed to get section(%d) header from %s\n", 1215 - idx, path); 1216 - goto done; 1217 - } 1218 - name = elf_strptr(elf, shstrndx, sh.sh_name); 1219 - if (!name) { 1220 - pr_warn("failed to get section(%d) name from %s\n", 1221 - idx, path); 1222 - goto done; 1223 - } 1224 - if (strcmp(name, BTF_ELF_SEC) == 0) { 1225 - btf_data = elf_getdata(scn, 0); 1226 - if (!btf_data) { 1227 - pr_warn("failed to get section(%d, %s) data from %s\n", 1228 - idx, name, path); 1229 - goto done; 1230 - } 1231 - continue; 1232 - } else if (btf_ext && strcmp(name, BTF_EXT_ELF_SEC) == 0) { 1233 - btf_ext_data = elf_getdata(scn, 0); 1234 - if (!btf_ext_data) { 1235 - pr_warn("failed to get section(%d, %s) data from %s\n", 1236 - idx, name, path); 1237 - goto done; 1238 - } 1239 - continue; 1240 - } 1241 - } 1242 - 1243 - if (!btf_data) { 1120 + if (!secs.btf_data) { 1244 1121 pr_warn("failed to find '%s' ELF section in %s\n", BTF_ELF_SEC, path); 1245 1122 err = -ENODATA; 1246 1123 goto done; 1247 1124 } 1248 - btf = btf_new(btf_data->d_buf, btf_data->d_size, base_btf); 1249 - err = libbpf_get_error(btf); 1250 - if (err) 1125 + 1126 + if (secs.btf_base_data) { 1127 + dist_base_btf = btf_new(secs.btf_base_data->d_buf, secs.btf_base_data->d_size, 1128 + NULL); 1129 + if (IS_ERR(dist_base_btf)) { 1130 + err = PTR_ERR(dist_base_btf); 1131 + dist_base_btf = NULL; 1132 + goto done; 1133 + } 1134 + } 1135 + 1136 + btf = btf_new(secs.btf_data->d_buf, secs.btf_data->d_size, 1137 + dist_base_btf ?: base_btf); 1138 + if (IS_ERR(btf)) { 1139 + err = PTR_ERR(btf); 1251 1140 goto done; 1141 + } 1142 + if (dist_base_btf && base_btf) { 1143 + err = btf__relocate(btf, base_btf); 1144 + if (err) 1145 + goto done; 1146 + btf__free(dist_base_btf); 1147 + dist_base_btf = NULL; 1148 + } 1149 + 1150 + if (dist_base_btf) 1151 + btf->owns_base = true; 1252 1152 1253 1153 switch (gelf_getclass(elf)) { 1254 1154 case ELFCLASS32: ··· 1237 1187 break; 1238 1188 } 1239 1189 1240 - if (btf_ext && btf_ext_data) { 1241 - *btf_ext = btf_ext__new(btf_ext_data->d_buf, btf_ext_data->d_size); 1242 - err = libbpf_get_error(*btf_ext); 1243 - if (err) 1190 + if (btf_ext && secs.btf_ext_data) { 1191 + *btf_ext = btf_ext__new(secs.btf_ext_data->d_buf, secs.btf_ext_data->d_size); 1192 + if (IS_ERR(*btf_ext)) { 1193 + err = PTR_ERR(*btf_ext); 1244 1194 goto done; 1195 + } 1245 1196 } else if (btf_ext) { 1246 1197 *btf_ext = NULL; 1247 1198 } ··· 1256 1205 1257 1206 if (btf_ext) 1258 1207 btf_ext__free(*btf_ext); 1208 + btf__free(dist_base_btf); 1259 1209 btf__free(btf); 1260 1210 1261 1211 return ERR_PTR(err); ··· 1822 1770 return 0; 1823 1771 } 1824 1772 1825 - int btf__add_type(struct btf *btf, const struct btf *src_btf, const struct btf_type *src_type) 1773 + static int btf_add_type(struct btf_pipe *p, const struct btf_type *src_type) 1826 1774 { 1827 - struct btf_pipe p = { .src = src_btf, .dst = btf }; 1828 1775 struct btf_field_iter it; 1829 1776 struct btf_type *t; 1830 1777 __u32 *str_off; ··· 1834 1783 return libbpf_err(sz); 1835 1784 1836 1785 /* deconstruct BTF, if necessary, and invalidate raw_data */ 1837 - if (btf_ensure_modifiable(btf)) 1786 + if (btf_ensure_modifiable(p->dst)) 1838 1787 return libbpf_err(-ENOMEM); 1839 1788 1840 - t = btf_add_type_mem(btf, sz); 1789 + t = btf_add_type_mem(p->dst, sz); 1841 1790 if (!t) 1842 1791 return libbpf_err(-ENOMEM); 1843 1792 ··· 1848 1797 return libbpf_err(err); 1849 1798 1850 1799 while ((str_off = btf_field_iter_next(&it))) { 1851 - err = btf_rewrite_str(&p, str_off); 1800 + err = btf_rewrite_str(p, str_off); 1852 1801 if (err) 1853 1802 return libbpf_err(err); 1854 1803 } 1855 1804 1856 - return btf_commit_type(btf, sz); 1805 + return btf_commit_type(p->dst, sz); 1806 + } 1807 + 1808 + int btf__add_type(struct btf *btf, const struct btf *src_btf, const struct btf_type *src_type) 1809 + { 1810 + struct btf_pipe p = { .src = src_btf, .dst = btf }; 1811 + 1812 + return btf_add_type(&p, src_type); 1857 1813 } 1858 1814 1859 1815 static size_t btf_dedup_identity_hash_fn(long key, void *ctx); ··· 5333 5275 } 5334 5276 5335 5277 return 0; 5278 + } 5279 + 5280 + struct btf_distill { 5281 + struct btf_pipe pipe; 5282 + int *id_map; 5283 + unsigned int split_start_id; 5284 + unsigned int split_start_str; 5285 + int diff_id; 5286 + }; 5287 + 5288 + static int btf_add_distilled_type_ids(struct btf_distill *dist, __u32 i) 5289 + { 5290 + struct btf_type *split_t = btf_type_by_id(dist->pipe.src, i); 5291 + struct btf_field_iter it; 5292 + __u32 *id; 5293 + int err; 5294 + 5295 + err = btf_field_iter_init(&it, split_t, BTF_FIELD_ITER_IDS); 5296 + if (err) 5297 + return err; 5298 + while ((id = btf_field_iter_next(&it))) { 5299 + struct btf_type *base_t; 5300 + 5301 + if (!*id) 5302 + continue; 5303 + /* split BTF id, not needed */ 5304 + if (*id >= dist->split_start_id) 5305 + continue; 5306 + /* already added ? */ 5307 + if (dist->id_map[*id] > 0) 5308 + continue; 5309 + 5310 + /* only a subset of base BTF types should be referenced from 5311 + * split BTF; ensure nothing unexpected is referenced. 5312 + */ 5313 + base_t = btf_type_by_id(dist->pipe.src, *id); 5314 + switch (btf_kind(base_t)) { 5315 + case BTF_KIND_INT: 5316 + case BTF_KIND_FLOAT: 5317 + case BTF_KIND_FWD: 5318 + case BTF_KIND_ARRAY: 5319 + case BTF_KIND_STRUCT: 5320 + case BTF_KIND_UNION: 5321 + case BTF_KIND_TYPEDEF: 5322 + case BTF_KIND_ENUM: 5323 + case BTF_KIND_ENUM64: 5324 + case BTF_KIND_PTR: 5325 + case BTF_KIND_CONST: 5326 + case BTF_KIND_RESTRICT: 5327 + case BTF_KIND_VOLATILE: 5328 + case BTF_KIND_FUNC_PROTO: 5329 + case BTF_KIND_TYPE_TAG: 5330 + dist->id_map[*id] = *id; 5331 + break; 5332 + default: 5333 + pr_warn("unexpected reference to base type[%u] of kind [%u] when creating distilled base BTF.\n", 5334 + *id, btf_kind(base_t)); 5335 + return -EINVAL; 5336 + } 5337 + /* If a base type is used, ensure types it refers to are 5338 + * marked as used also; so for example if we find a PTR to INT 5339 + * we need both the PTR and INT. 5340 + * 5341 + * The only exception is named struct/unions, since distilled 5342 + * base BTF composite types have no members. 5343 + */ 5344 + if (btf_is_composite(base_t) && base_t->name_off) 5345 + continue; 5346 + err = btf_add_distilled_type_ids(dist, *id); 5347 + if (err) 5348 + return err; 5349 + } 5350 + return 0; 5351 + } 5352 + 5353 + static int btf_add_distilled_types(struct btf_distill *dist) 5354 + { 5355 + bool adding_to_base = dist->pipe.dst->start_id == 1; 5356 + int id = btf__type_cnt(dist->pipe.dst); 5357 + struct btf_type *t; 5358 + int i, err = 0; 5359 + 5360 + 5361 + /* Add types for each of the required references to either distilled 5362 + * base or split BTF, depending on type characteristics. 5363 + */ 5364 + for (i = 1; i < dist->split_start_id; i++) { 5365 + const char *name; 5366 + int kind; 5367 + 5368 + if (!dist->id_map[i]) 5369 + continue; 5370 + t = btf_type_by_id(dist->pipe.src, i); 5371 + kind = btf_kind(t); 5372 + name = btf__name_by_offset(dist->pipe.src, t->name_off); 5373 + 5374 + switch (kind) { 5375 + case BTF_KIND_INT: 5376 + case BTF_KIND_FLOAT: 5377 + case BTF_KIND_FWD: 5378 + /* Named int, float, fwd are added to base. */ 5379 + if (!adding_to_base) 5380 + continue; 5381 + err = btf_add_type(&dist->pipe, t); 5382 + break; 5383 + case BTF_KIND_STRUCT: 5384 + case BTF_KIND_UNION: 5385 + /* Named struct/union are added to base as 0-vlen 5386 + * struct/union of same size. Anonymous struct/unions 5387 + * are added to split BTF as-is. 5388 + */ 5389 + if (adding_to_base) { 5390 + if (!t->name_off) 5391 + continue; 5392 + err = btf_add_composite(dist->pipe.dst, kind, name, t->size); 5393 + } else { 5394 + if (t->name_off) 5395 + continue; 5396 + err = btf_add_type(&dist->pipe, t); 5397 + } 5398 + break; 5399 + case BTF_KIND_ENUM: 5400 + case BTF_KIND_ENUM64: 5401 + /* Named enum[64]s are added to base as a sized 5402 + * enum; relocation will match with appropriately-named 5403 + * and sized enum or enum64. 5404 + * 5405 + * Anonymous enums are added to split BTF as-is. 5406 + */ 5407 + if (adding_to_base) { 5408 + if (!t->name_off) 5409 + continue; 5410 + err = btf__add_enum(dist->pipe.dst, name, t->size); 5411 + } else { 5412 + if (t->name_off) 5413 + continue; 5414 + err = btf_add_type(&dist->pipe, t); 5415 + } 5416 + break; 5417 + case BTF_KIND_ARRAY: 5418 + case BTF_KIND_TYPEDEF: 5419 + case BTF_KIND_PTR: 5420 + case BTF_KIND_CONST: 5421 + case BTF_KIND_RESTRICT: 5422 + case BTF_KIND_VOLATILE: 5423 + case BTF_KIND_FUNC_PROTO: 5424 + case BTF_KIND_TYPE_TAG: 5425 + /* All other types are added to split BTF. */ 5426 + if (adding_to_base) 5427 + continue; 5428 + err = btf_add_type(&dist->pipe, t); 5429 + break; 5430 + default: 5431 + pr_warn("unexpected kind when adding base type '%s'[%u] of kind [%u] to distilled base BTF.\n", 5432 + name, i, kind); 5433 + return -EINVAL; 5434 + 5435 + } 5436 + if (err < 0) 5437 + break; 5438 + dist->id_map[i] = id++; 5439 + } 5440 + return err; 5441 + } 5442 + 5443 + /* Split BTF ids without a mapping will be shifted downwards since distilled 5444 + * base BTF is smaller than the original base BTF. For those that have a 5445 + * mapping (either to base or updated split BTF), update the id based on 5446 + * that mapping. 5447 + */ 5448 + static int btf_update_distilled_type_ids(struct btf_distill *dist, __u32 i) 5449 + { 5450 + struct btf_type *t = btf_type_by_id(dist->pipe.dst, i); 5451 + struct btf_field_iter it; 5452 + __u32 *id; 5453 + int err; 5454 + 5455 + err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS); 5456 + if (err) 5457 + return err; 5458 + while ((id = btf_field_iter_next(&it))) { 5459 + if (dist->id_map[*id]) 5460 + *id = dist->id_map[*id]; 5461 + else if (*id >= dist->split_start_id) 5462 + *id -= dist->diff_id; 5463 + } 5464 + return 0; 5465 + } 5466 + 5467 + /* Create updated split BTF with distilled base BTF; distilled base BTF 5468 + * consists of BTF information required to clarify the types that split 5469 + * BTF refers to, omitting unneeded details. Specifically it will contain 5470 + * base types and memberless definitions of named structs, unions and enumerated 5471 + * types. Associated reference types like pointers, arrays and anonymous 5472 + * structs, unions and enumerated types will be added to split BTF. 5473 + * Size is recorded for named struct/unions to help guide matching to the 5474 + * target base BTF during later relocation. 5475 + * 5476 + * The only case where structs, unions or enumerated types are fully represented 5477 + * is when they are anonymous; in such cases, the anonymous type is added to 5478 + * split BTF in full. 5479 + * 5480 + * We return newly-created split BTF where the split BTF refers to a newly-created 5481 + * distilled base BTF. Both must be freed separately by the caller. 5482 + */ 5483 + int btf__distill_base(const struct btf *src_btf, struct btf **new_base_btf, 5484 + struct btf **new_split_btf) 5485 + { 5486 + struct btf *new_base = NULL, *new_split = NULL; 5487 + const struct btf *old_base; 5488 + unsigned int n = btf__type_cnt(src_btf); 5489 + struct btf_distill dist = {}; 5490 + struct btf_type *t; 5491 + int i, err = 0; 5492 + 5493 + /* src BTF must be split BTF. */ 5494 + old_base = btf__base_btf(src_btf); 5495 + if (!new_base_btf || !new_split_btf || !old_base) 5496 + return libbpf_err(-EINVAL); 5497 + 5498 + new_base = btf__new_empty(); 5499 + if (!new_base) 5500 + return libbpf_err(-ENOMEM); 5501 + dist.id_map = calloc(n, sizeof(*dist.id_map)); 5502 + if (!dist.id_map) { 5503 + err = -ENOMEM; 5504 + goto done; 5505 + } 5506 + dist.pipe.src = src_btf; 5507 + dist.pipe.dst = new_base; 5508 + dist.pipe.str_off_map = hashmap__new(btf_dedup_identity_hash_fn, btf_dedup_equal_fn, NULL); 5509 + if (IS_ERR(dist.pipe.str_off_map)) { 5510 + err = -ENOMEM; 5511 + goto done; 5512 + } 5513 + dist.split_start_id = btf__type_cnt(old_base); 5514 + dist.split_start_str = old_base->hdr->str_len; 5515 + 5516 + /* Pass over src split BTF; generate the list of base BTF type ids it 5517 + * references; these will constitute our distilled BTF set to be 5518 + * distributed over base and split BTF as appropriate. 5519 + */ 5520 + for (i = src_btf->start_id; i < n; i++) { 5521 + err = btf_add_distilled_type_ids(&dist, i); 5522 + if (err < 0) 5523 + goto done; 5524 + } 5525 + /* Next add types for each of the required references to base BTF and split BTF 5526 + * in turn. 5527 + */ 5528 + err = btf_add_distilled_types(&dist); 5529 + if (err < 0) 5530 + goto done; 5531 + 5532 + /* Create new split BTF with distilled base BTF as its base; the final 5533 + * state is split BTF with distilled base BTF that represents enough 5534 + * about its base references to allow it to be relocated with the base 5535 + * BTF available. 5536 + */ 5537 + new_split = btf__new_empty_split(new_base); 5538 + if (!new_split_btf) { 5539 + err = -errno; 5540 + goto done; 5541 + } 5542 + dist.pipe.dst = new_split; 5543 + /* First add all split types */ 5544 + for (i = src_btf->start_id; i < n; i++) { 5545 + t = btf_type_by_id(src_btf, i); 5546 + err = btf_add_type(&dist.pipe, t); 5547 + if (err < 0) 5548 + goto done; 5549 + } 5550 + /* Now add distilled types to split BTF that are not added to base. */ 5551 + err = btf_add_distilled_types(&dist); 5552 + if (err < 0) 5553 + goto done; 5554 + 5555 + /* All split BTF ids will be shifted downwards since there are less base 5556 + * BTF ids in distilled base BTF. 5557 + */ 5558 + dist.diff_id = dist.split_start_id - btf__type_cnt(new_base); 5559 + 5560 + n = btf__type_cnt(new_split); 5561 + /* Now update base/split BTF ids. */ 5562 + for (i = 1; i < n; i++) { 5563 + err = btf_update_distilled_type_ids(&dist, i); 5564 + if (err < 0) 5565 + break; 5566 + } 5567 + done: 5568 + free(dist.id_map); 5569 + hashmap__free(dist.pipe.str_off_map); 5570 + if (err) { 5571 + btf__free(new_split); 5572 + btf__free(new_base); 5573 + return libbpf_err(err); 5574 + } 5575 + *new_base_btf = new_base; 5576 + *new_split_btf = new_split; 5577 + 5578 + return 0; 5579 + } 5580 + 5581 + const struct btf_header *btf_header(const struct btf *btf) 5582 + { 5583 + return btf->hdr; 5584 + } 5585 + 5586 + void btf_set_base_btf(struct btf *btf, const struct btf *base_btf) 5587 + { 5588 + btf->base_btf = (struct btf *)base_btf; 5589 + btf->start_id = btf__type_cnt(base_btf); 5590 + btf->start_str_off = base_btf->hdr->str_len; 5591 + } 5592 + 5593 + int btf__relocate(struct btf *btf, const struct btf *base_btf) 5594 + { 5595 + int err = btf_relocate(btf, base_btf, NULL); 5596 + 5597 + if (!err) 5598 + btf->owns_base = false; 5599 + return libbpf_err(err); 5336 5600 }
+36
tools/lib/bpf/btf.h
··· 18 18 19 19 #define BTF_ELF_SEC ".BTF" 20 20 #define BTF_EXT_ELF_SEC ".BTF.ext" 21 + #define BTF_BASE_ELF_SEC ".BTF.base" 21 22 #define MAPS_ELF_SEC ".maps" 22 23 23 24 struct btf; ··· 107 106 * always set to error code as well. 108 107 */ 109 108 LIBBPF_API struct btf *btf__new_empty_split(struct btf *base_btf); 109 + 110 + /** 111 + * @brief **btf__distill_base()** creates new versions of the split BTF 112 + * *src_btf* and its base BTF. The new base BTF will only contain the types 113 + * needed to improve robustness of the split BTF to small changes in base BTF. 114 + * When that split BTF is loaded against a (possibly changed) base, this 115 + * distilled base BTF will help update references to that (possibly changed) 116 + * base BTF. 117 + * 118 + * Both the new split and its associated new base BTF must be freed by 119 + * the caller. 120 + * 121 + * If successful, 0 is returned and **new_base_btf** and **new_split_btf** 122 + * will point at new base/split BTF. Both the new split and its associated 123 + * new base BTF must be freed by the caller. 124 + * 125 + * A negative value is returned on error and the thread-local `errno` variable 126 + * is set to the error code as well. 127 + */ 128 + LIBBPF_API int btf__distill_base(const struct btf *src_btf, struct btf **new_base_btf, 129 + struct btf **new_split_btf); 110 130 111 131 LIBBPF_API struct btf *btf__parse(const char *path, struct btf_ext **btf_ext); 112 132 LIBBPF_API struct btf *btf__parse_split(const char *path, struct btf *base_btf); ··· 252 230 #define btf_dedup_opts__last_field force_collisions 253 231 254 232 LIBBPF_API int btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts); 233 + 234 + /** 235 + * @brief **btf__relocate()** will check the split BTF *btf* for references 236 + * to base BTF kinds, and verify those references are compatible with 237 + * *base_btf*; if they are, *btf* is adjusted such that is re-parented to 238 + * *base_btf* and type ids and strings are adjusted to accommodate this. 239 + * 240 + * If successful, 0 is returned and **btf** now has **base_btf** as its 241 + * base. 242 + * 243 + * A negative value is returned on error and the thread-local `errno` variable 244 + * is set to the error code as well. 245 + */ 246 + LIBBPF_API int btf__relocate(struct btf *btf, const struct btf *base_btf); 255 247 256 248 struct btf_dump; 257 249
+506
tools/lib/bpf/btf_relocate.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2024, Oracle and/or its affiliates. */ 3 + 4 + #ifndef _GNU_SOURCE 5 + #define _GNU_SOURCE 6 + #endif 7 + 8 + #include "btf.h" 9 + #include "bpf.h" 10 + #include "libbpf.h" 11 + #include "libbpf_internal.h" 12 + 13 + struct btf; 14 + 15 + struct btf_relocate { 16 + struct btf *btf; 17 + const struct btf *base_btf; 18 + const struct btf *dist_base_btf; 19 + unsigned int nr_base_types; 20 + unsigned int nr_split_types; 21 + unsigned int nr_dist_base_types; 22 + int dist_str_len; 23 + int base_str_len; 24 + __u32 *id_map; 25 + __u32 *str_map; 26 + }; 27 + 28 + /* Set temporarily in relocation id_map if distilled base struct/union is 29 + * embedded in a split BTF struct/union; in such a case, size information must 30 + * match between distilled base BTF and base BTF representation of type. 31 + */ 32 + #define BTF_IS_EMBEDDED ((__u32)-1) 33 + 34 + /* <name, size, id> triple used in sorting/searching distilled base BTF. */ 35 + struct btf_name_info { 36 + const char *name; 37 + /* set when search requires a size match */ 38 + int needs_size:1, 39 + size:31; 40 + __u32 id; 41 + }; 42 + 43 + static int btf_relocate_rewrite_type_id(struct btf_relocate *r, __u32 i) 44 + { 45 + struct btf_type *t = btf_type_by_id(r->btf, i); 46 + struct btf_field_iter it; 47 + __u32 *id; 48 + int err; 49 + 50 + err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS); 51 + if (err) 52 + return err; 53 + 54 + while ((id = btf_field_iter_next(&it))) 55 + *id = r->id_map[*id]; 56 + return 0; 57 + } 58 + 59 + /* Simple string comparison used for sorting within BTF, since all distilled 60 + * types are named. If strings match, and size is non-zero for both elements 61 + * fall back to using size for ordering. 62 + */ 63 + static int cmp_btf_name_size(const void *n1, const void *n2) 64 + { 65 + const struct btf_name_info *ni1 = n1; 66 + const struct btf_name_info *ni2 = n2; 67 + int name_diff = strcmp(ni1->name, ni2->name); 68 + 69 + if (!name_diff && ni1->needs_size && ni2->needs_size) 70 + return ni2->size - ni1->size; 71 + return name_diff; 72 + } 73 + 74 + /* Binary search with a small twist; find leftmost element that matches 75 + * so that we can then iterate through all exact matches. So for example 76 + * searching { "a", "bb", "bb", "c" } we would always match on the 77 + * leftmost "bb". 78 + */ 79 + static struct btf_name_info *search_btf_name_size(struct btf_name_info *key, 80 + struct btf_name_info *vals, 81 + int nelems) 82 + { 83 + struct btf_name_info *ret = NULL; 84 + int high = nelems - 1; 85 + int low = 0; 86 + 87 + while (low <= high) { 88 + int mid = (low + high)/2; 89 + struct btf_name_info *val = &vals[mid]; 90 + int diff = cmp_btf_name_size(key, val); 91 + 92 + if (diff == 0) 93 + ret = val; 94 + /* even if found, keep searching for leftmost match */ 95 + if (diff <= 0) 96 + high = mid - 1; 97 + else 98 + low = mid + 1; 99 + } 100 + return ret; 101 + } 102 + 103 + /* If a member of a split BTF struct/union refers to a base BTF 104 + * struct/union, mark that struct/union id temporarily in the id_map 105 + * with BTF_IS_EMBEDDED. Members can be const/restrict/volatile/typedef 106 + * reference types, but if a pointer is encountered, the type is no longer 107 + * considered embedded. 108 + */ 109 + static int btf_mark_embedded_composite_type_ids(struct btf_relocate *r, __u32 i) 110 + { 111 + struct btf_type *t = btf_type_by_id(r->btf, i); 112 + struct btf_field_iter it; 113 + __u32 *id; 114 + int err; 115 + 116 + if (!btf_is_composite(t)) 117 + return 0; 118 + 119 + err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS); 120 + if (err) 121 + return err; 122 + 123 + while ((id = btf_field_iter_next(&it))) { 124 + __u32 next_id = *id; 125 + 126 + while (next_id) { 127 + t = btf_type_by_id(r->btf, next_id); 128 + switch (btf_kind(t)) { 129 + case BTF_KIND_CONST: 130 + case BTF_KIND_RESTRICT: 131 + case BTF_KIND_VOLATILE: 132 + case BTF_KIND_TYPEDEF: 133 + case BTF_KIND_TYPE_TAG: 134 + next_id = t->type; 135 + break; 136 + case BTF_KIND_ARRAY: { 137 + struct btf_array *a = btf_array(t); 138 + 139 + next_id = a->type; 140 + break; 141 + } 142 + case BTF_KIND_STRUCT: 143 + case BTF_KIND_UNION: 144 + if (next_id < r->nr_dist_base_types) 145 + r->id_map[next_id] = BTF_IS_EMBEDDED; 146 + next_id = 0; 147 + break; 148 + default: 149 + next_id = 0; 150 + break; 151 + } 152 + } 153 + } 154 + 155 + return 0; 156 + } 157 + 158 + /* Build a map from distilled base BTF ids to base BTF ids. To do so, iterate 159 + * through base BTF looking up distilled type (using binary search) equivalents. 160 + */ 161 + static int btf_relocate_map_distilled_base(struct btf_relocate *r) 162 + { 163 + struct btf_name_info *dist_base_info_sorted, *dist_base_info_sorted_end; 164 + struct btf_type *base_t, *dist_t; 165 + __u8 *base_name_cnt = NULL; 166 + int err = 0; 167 + __u32 id; 168 + 169 + /* generate a sort index array of name/type ids sorted by name for 170 + * distilled base BTF to speed name-based lookups. 171 + */ 172 + dist_base_info_sorted = calloc(r->nr_dist_base_types, sizeof(*dist_base_info_sorted)); 173 + if (!dist_base_info_sorted) { 174 + err = -ENOMEM; 175 + goto done; 176 + } 177 + dist_base_info_sorted_end = dist_base_info_sorted + r->nr_dist_base_types; 178 + for (id = 0; id < r->nr_dist_base_types; id++) { 179 + dist_t = btf_type_by_id(r->dist_base_btf, id); 180 + dist_base_info_sorted[id].name = btf__name_by_offset(r->dist_base_btf, 181 + dist_t->name_off); 182 + dist_base_info_sorted[id].id = id; 183 + dist_base_info_sorted[id].size = dist_t->size; 184 + dist_base_info_sorted[id].needs_size = true; 185 + } 186 + qsort(dist_base_info_sorted, r->nr_dist_base_types, sizeof(*dist_base_info_sorted), 187 + cmp_btf_name_size); 188 + 189 + /* Mark distilled base struct/union members of split BTF structs/unions 190 + * in id_map with BTF_IS_EMBEDDED; this signals that these types 191 + * need to match both name and size, otherwise embeddding the base 192 + * struct/union in the split type is invalid. 193 + */ 194 + for (id = r->nr_dist_base_types; id < r->nr_split_types; id++) { 195 + err = btf_mark_embedded_composite_type_ids(r, id); 196 + if (err) 197 + goto done; 198 + } 199 + 200 + /* Collect name counts for composite types in base BTF. If multiple 201 + * instances of a struct/union of the same name exist, we need to use 202 + * size to determine which to map to since name alone is ambiguous. 203 + */ 204 + base_name_cnt = calloc(r->base_str_len, sizeof(*base_name_cnt)); 205 + if (!base_name_cnt) { 206 + err = -ENOMEM; 207 + goto done; 208 + } 209 + for (id = 1; id < r->nr_base_types; id++) { 210 + base_t = btf_type_by_id(r->base_btf, id); 211 + if (!btf_is_composite(base_t) || !base_t->name_off) 212 + continue; 213 + if (base_name_cnt[base_t->name_off] < 255) 214 + base_name_cnt[base_t->name_off]++; 215 + } 216 + 217 + /* Now search base BTF for matching distilled base BTF types. */ 218 + for (id = 1; id < r->nr_base_types; id++) { 219 + struct btf_name_info *dist_name_info, *dist_name_info_next = NULL; 220 + struct btf_name_info base_name_info = {}; 221 + int dist_kind, base_kind; 222 + 223 + base_t = btf_type_by_id(r->base_btf, id); 224 + /* distilled base consists of named types only. */ 225 + if (!base_t->name_off) 226 + continue; 227 + base_kind = btf_kind(base_t); 228 + base_name_info.id = id; 229 + base_name_info.name = btf__name_by_offset(r->base_btf, base_t->name_off); 230 + switch (base_kind) { 231 + case BTF_KIND_INT: 232 + case BTF_KIND_FLOAT: 233 + case BTF_KIND_ENUM: 234 + case BTF_KIND_ENUM64: 235 + /* These types should match both name and size */ 236 + base_name_info.needs_size = true; 237 + base_name_info.size = base_t->size; 238 + break; 239 + case BTF_KIND_FWD: 240 + /* No size considerations for fwds. */ 241 + break; 242 + case BTF_KIND_STRUCT: 243 + case BTF_KIND_UNION: 244 + /* Size only needs to be used for struct/union if there 245 + * are multiple types in base BTF with the same name. 246 + * If there are multiple _distilled_ types with the same 247 + * name (a very unlikely scenario), that doesn't matter 248 + * unless corresponding _base_ types to match them are 249 + * missing. 250 + */ 251 + base_name_info.needs_size = base_name_cnt[base_t->name_off] > 1; 252 + base_name_info.size = base_t->size; 253 + break; 254 + default: 255 + continue; 256 + } 257 + /* iterate over all matching distilled base types */ 258 + for (dist_name_info = search_btf_name_size(&base_name_info, dist_base_info_sorted, 259 + r->nr_dist_base_types); 260 + dist_name_info != NULL; dist_name_info = dist_name_info_next) { 261 + /* Are there more distilled matches to process after 262 + * this one? 263 + */ 264 + dist_name_info_next = dist_name_info + 1; 265 + if (dist_name_info_next >= dist_base_info_sorted_end || 266 + cmp_btf_name_size(&base_name_info, dist_name_info_next)) 267 + dist_name_info_next = NULL; 268 + 269 + if (!dist_name_info->id || dist_name_info->id > r->nr_dist_base_types) { 270 + pr_warn("base BTF id [%d] maps to invalid distilled base BTF id [%d]\n", 271 + id, dist_name_info->id); 272 + err = -EINVAL; 273 + goto done; 274 + } 275 + dist_t = btf_type_by_id(r->dist_base_btf, dist_name_info->id); 276 + dist_kind = btf_kind(dist_t); 277 + 278 + /* Validate that the found distilled type is compatible. 279 + * Do not error out on mismatch as another match may 280 + * occur for an identically-named type. 281 + */ 282 + switch (dist_kind) { 283 + case BTF_KIND_FWD: 284 + switch (base_kind) { 285 + case BTF_KIND_FWD: 286 + if (btf_kflag(dist_t) != btf_kflag(base_t)) 287 + continue; 288 + break; 289 + case BTF_KIND_STRUCT: 290 + if (btf_kflag(base_t)) 291 + continue; 292 + break; 293 + case BTF_KIND_UNION: 294 + if (!btf_kflag(base_t)) 295 + continue; 296 + break; 297 + default: 298 + continue; 299 + } 300 + break; 301 + case BTF_KIND_INT: 302 + if (dist_kind != base_kind || 303 + btf_int_encoding(base_t) != btf_int_encoding(dist_t)) 304 + continue; 305 + break; 306 + case BTF_KIND_FLOAT: 307 + if (dist_kind != base_kind) 308 + continue; 309 + break; 310 + case BTF_KIND_ENUM: 311 + /* ENUM and ENUM64 are encoded as sized ENUM in 312 + * distilled base BTF. 313 + */ 314 + if (base_kind != dist_kind && base_kind != BTF_KIND_ENUM64) 315 + continue; 316 + break; 317 + case BTF_KIND_STRUCT: 318 + case BTF_KIND_UNION: 319 + /* size verification is required for embedded 320 + * struct/unions. 321 + */ 322 + if (r->id_map[dist_name_info->id] == BTF_IS_EMBEDDED && 323 + base_t->size != dist_t->size) 324 + continue; 325 + break; 326 + default: 327 + continue; 328 + } 329 + if (r->id_map[dist_name_info->id] && 330 + r->id_map[dist_name_info->id] != BTF_IS_EMBEDDED) { 331 + /* we already have a match; this tells us that 332 + * multiple base types of the same name 333 + * have the same size, since for cases where 334 + * multiple types have the same name we match 335 + * on name and size. In this case, we have 336 + * no way of determining which to relocate 337 + * to in base BTF, so error out. 338 + */ 339 + pr_warn("distilled base BTF type '%s' [%u], size %u has multiple candidates of the same size (ids [%u, %u]) in base BTF\n", 340 + base_name_info.name, dist_name_info->id, 341 + base_t->size, id, r->id_map[dist_name_info->id]); 342 + err = -EINVAL; 343 + goto done; 344 + } 345 + /* map id and name */ 346 + r->id_map[dist_name_info->id] = id; 347 + r->str_map[dist_t->name_off] = base_t->name_off; 348 + } 349 + } 350 + /* ensure all distilled BTF ids now have a mapping... */ 351 + for (id = 1; id < r->nr_dist_base_types; id++) { 352 + const char *name; 353 + 354 + if (r->id_map[id] && r->id_map[id] != BTF_IS_EMBEDDED) 355 + continue; 356 + dist_t = btf_type_by_id(r->dist_base_btf, id); 357 + name = btf__name_by_offset(r->dist_base_btf, dist_t->name_off); 358 + pr_warn("distilled base BTF type '%s' [%d] is not mapped to base BTF id\n", 359 + name, id); 360 + err = -EINVAL; 361 + break; 362 + } 363 + done: 364 + free(base_name_cnt); 365 + free(dist_base_info_sorted); 366 + return err; 367 + } 368 + 369 + /* distilled base should only have named int/float/enum/fwd/struct/union types. */ 370 + static int btf_relocate_validate_distilled_base(struct btf_relocate *r) 371 + { 372 + unsigned int i; 373 + 374 + for (i = 1; i < r->nr_dist_base_types; i++) { 375 + struct btf_type *t = btf_type_by_id(r->dist_base_btf, i); 376 + int kind = btf_kind(t); 377 + 378 + switch (kind) { 379 + case BTF_KIND_INT: 380 + case BTF_KIND_FLOAT: 381 + case BTF_KIND_ENUM: 382 + case BTF_KIND_STRUCT: 383 + case BTF_KIND_UNION: 384 + case BTF_KIND_FWD: 385 + if (t->name_off) 386 + break; 387 + pr_warn("type [%d], kind [%d] is invalid for distilled base BTF; it is anonymous\n", 388 + i, kind); 389 + return -EINVAL; 390 + default: 391 + pr_warn("type [%d] in distilled based BTF has unexpected kind [%d]\n", 392 + i, kind); 393 + return -EINVAL; 394 + } 395 + } 396 + return 0; 397 + } 398 + 399 + static int btf_relocate_rewrite_strs(struct btf_relocate *r, __u32 i) 400 + { 401 + struct btf_type *t = btf_type_by_id(r->btf, i); 402 + struct btf_field_iter it; 403 + __u32 *str_off; 404 + int off, err; 405 + 406 + err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_STRS); 407 + if (err) 408 + return err; 409 + 410 + while ((str_off = btf_field_iter_next(&it))) { 411 + if (!*str_off) 412 + continue; 413 + if (*str_off >= r->dist_str_len) { 414 + *str_off += r->base_str_len - r->dist_str_len; 415 + } else { 416 + off = r->str_map[*str_off]; 417 + if (!off) { 418 + pr_warn("string '%s' [offset %u] is not mapped to base BTF", 419 + btf__str_by_offset(r->btf, off), *str_off); 420 + return -ENOENT; 421 + } 422 + *str_off = off; 423 + } 424 + } 425 + return 0; 426 + } 427 + 428 + /* If successful, output of relocation is updated BTF with base BTF pointing 429 + * at base_btf, and type ids, strings adjusted accordingly. 430 + */ 431 + int btf_relocate(struct btf *btf, const struct btf *base_btf, __u32 **id_map) 432 + { 433 + unsigned int nr_types = btf__type_cnt(btf); 434 + const struct btf_header *dist_base_hdr; 435 + const struct btf_header *base_hdr; 436 + struct btf_relocate r = {}; 437 + int err = 0; 438 + __u32 id, i; 439 + 440 + r.dist_base_btf = btf__base_btf(btf); 441 + if (!base_btf || r.dist_base_btf == base_btf) 442 + return -EINVAL; 443 + 444 + r.nr_dist_base_types = btf__type_cnt(r.dist_base_btf); 445 + r.nr_base_types = btf__type_cnt(base_btf); 446 + r.nr_split_types = nr_types - r.nr_dist_base_types; 447 + r.btf = btf; 448 + r.base_btf = base_btf; 449 + 450 + r.id_map = calloc(nr_types, sizeof(*r.id_map)); 451 + r.str_map = calloc(btf_header(r.dist_base_btf)->str_len, sizeof(*r.str_map)); 452 + dist_base_hdr = btf_header(r.dist_base_btf); 453 + base_hdr = btf_header(r.base_btf); 454 + r.dist_str_len = dist_base_hdr->str_len; 455 + r.base_str_len = base_hdr->str_len; 456 + if (!r.id_map || !r.str_map) { 457 + err = -ENOMEM; 458 + goto err_out; 459 + } 460 + 461 + err = btf_relocate_validate_distilled_base(&r); 462 + if (err) 463 + goto err_out; 464 + 465 + /* Split BTF ids need to be adjusted as base and distilled base 466 + * have different numbers of types, changing the start id of split 467 + * BTF. 468 + */ 469 + for (id = r.nr_dist_base_types; id < nr_types; id++) 470 + r.id_map[id] = id + r.nr_base_types - r.nr_dist_base_types; 471 + 472 + /* Build a map from distilled base ids to actual base BTF ids; it is used 473 + * to update split BTF id references. Also build a str_map mapping from 474 + * distilled base BTF names to base BTF names. 475 + */ 476 + err = btf_relocate_map_distilled_base(&r); 477 + if (err) 478 + goto err_out; 479 + 480 + /* Next, rewrite type ids in split BTF, replacing split ids with updated 481 + * ids based on number of types in base BTF, and base ids with 482 + * relocated ids from base_btf. 483 + */ 484 + for (i = 0, id = r.nr_dist_base_types; i < r.nr_split_types; i++, id++) { 485 + err = btf_relocate_rewrite_type_id(&r, id); 486 + if (err) 487 + goto err_out; 488 + } 489 + /* String offsets now need to be updated using the str_map. */ 490 + for (i = 0; i < r.nr_split_types; i++) { 491 + err = btf_relocate_rewrite_strs(&r, i + r.nr_dist_base_types); 492 + if (err) 493 + goto err_out; 494 + } 495 + /* Finally reset base BTF to be base_btf */ 496 + btf_set_base_btf(btf, base_btf); 497 + 498 + if (id_map) { 499 + *id_map = r.id_map; 500 + r.id_map = NULL; 501 + } 502 + err_out: 503 + free(r.id_map); 504 + free(r.str_map); 505 + return err; 506 + }
+2
tools/lib/bpf/libbpf.map
··· 419 419 420 420 LIBBPF_1.5.0 { 421 421 global: 422 + btf__distill_base; 423 + btf__relocate; 422 424 bpf_map__autoattach; 423 425 bpf_map__set_autoattach; 424 426 bpf_program__attach_sockmap;
+3
tools/lib/bpf/libbpf_internal.h
··· 234 234 struct btf_type *btf_type_by_id(const struct btf *btf, __u32 type_id); 235 235 const char *btf_kind_str(const struct btf_type *t); 236 236 const struct btf_type *skip_mods_and_typedefs(const struct btf *btf, __u32 id, __u32 *res_id); 237 + const struct btf_header *btf_header(const struct btf *btf); 238 + void btf_set_base_btf(struct btf *btf, const struct btf *base_btf); 239 + int btf_relocate(struct btf *btf, const struct btf *base_btf, __u32 **id_map); 237 240 238 241 static inline enum btf_func_linkage btf_func_linkage(const struct btf_type *t) 239 242 {
+552
tools/testing/selftests/bpf/prog_tests/btf_distill.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2024, Oracle and/or its affiliates. */ 3 + 4 + #include <test_progs.h> 5 + #include <bpf/btf.h> 6 + #include "btf_helpers.h" 7 + 8 + /* Fabricate base, split BTF with references to base types needed; then create 9 + * split BTF with distilled base BTF and ensure expectations are met: 10 + * - only referenced base types from split BTF are present 11 + * - struct/union/enum are represented as empty unless anonymous, when they 12 + * are represented in full in split BTF 13 + */ 14 + static void test_distilled_base(void) 15 + { 16 + struct btf *btf1 = NULL, *btf2 = NULL, *btf3 = NULL, *btf4 = NULL; 17 + 18 + btf1 = btf__new_empty(); 19 + if (!ASSERT_OK_PTR(btf1, "empty_main_btf")) 20 + return; 21 + 22 + btf__add_int(btf1, "int", 4, BTF_INT_SIGNED); /* [1] int */ 23 + btf__add_ptr(btf1, 1); /* [2] ptr to int */ 24 + btf__add_struct(btf1, "s1", 8); /* [3] struct s1 { */ 25 + btf__add_field(btf1, "f1", 2, 0, 0); /* int *f1; */ 26 + /* } */ 27 + btf__add_struct(btf1, "", 12); /* [4] struct { */ 28 + btf__add_field(btf1, "f1", 1, 0, 0); /* int f1; */ 29 + btf__add_field(btf1, "f2", 3, 32, 0); /* struct s1 f2; */ 30 + /* } */ 31 + btf__add_int(btf1, "unsigned int", 4, 0); /* [5] unsigned int */ 32 + btf__add_union(btf1, "u1", 12); /* [6] union u1 { */ 33 + btf__add_field(btf1, "f1", 1, 0, 0); /* int f1; */ 34 + btf__add_field(btf1, "f2", 2, 0, 0); /* int *f2; */ 35 + /* } */ 36 + btf__add_union(btf1, "", 4); /* [7] union { */ 37 + btf__add_field(btf1, "f1", 1, 0, 0); /* int f1; */ 38 + /* } */ 39 + btf__add_enum(btf1, "e1", 4); /* [8] enum e1 { */ 40 + btf__add_enum_value(btf1, "v1", 1); /* v1 = 1; */ 41 + /* } */ 42 + btf__add_enum(btf1, "", 4); /* [9] enum { */ 43 + btf__add_enum_value(btf1, "av1", 2); /* av1 = 2; */ 44 + /* } */ 45 + btf__add_enum64(btf1, "e641", 8, true); /* [10] enum64 { */ 46 + btf__add_enum64_value(btf1, "v1", 1024); /* v1 = 1024; */ 47 + /* } */ 48 + btf__add_enum64(btf1, "", 8, true); /* [11] enum64 { */ 49 + btf__add_enum64_value(btf1, "v1", 1025); /* v1 = 1025; */ 50 + /* } */ 51 + btf__add_struct(btf1, "unneeded", 4); /* [12] struct unneeded { */ 52 + btf__add_field(btf1, "f1", 1, 0, 0); /* int f1; */ 53 + /* } */ 54 + btf__add_struct(btf1, "embedded", 4); /* [13] struct embedded { */ 55 + btf__add_field(btf1, "f1", 1, 0, 0); /* int f1; */ 56 + /* } */ 57 + btf__add_func_proto(btf1, 1); /* [14] int (*)(int *p1); */ 58 + btf__add_func_param(btf1, "p1", 1); 59 + 60 + btf__add_array(btf1, 1, 1, 3); /* [15] int [3]; */ 61 + 62 + btf__add_struct(btf1, "from_proto", 4); /* [16] struct from_proto { */ 63 + btf__add_field(btf1, "f1", 1, 0, 0); /* int f1; */ 64 + /* } */ 65 + btf__add_union(btf1, "u1", 4); /* [17] union u1 { */ 66 + btf__add_field(btf1, "f1", 1, 0, 0); /* int f1; */ 67 + /* } */ 68 + VALIDATE_RAW_BTF( 69 + btf1, 70 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 71 + "[2] PTR '(anon)' type_id=1", 72 + "[3] STRUCT 's1' size=8 vlen=1\n" 73 + "\t'f1' type_id=2 bits_offset=0", 74 + "[4] STRUCT '(anon)' size=12 vlen=2\n" 75 + "\t'f1' type_id=1 bits_offset=0\n" 76 + "\t'f2' type_id=3 bits_offset=32", 77 + "[5] INT 'unsigned int' size=4 bits_offset=0 nr_bits=32 encoding=(none)", 78 + "[6] UNION 'u1' size=12 vlen=2\n" 79 + "\t'f1' type_id=1 bits_offset=0\n" 80 + "\t'f2' type_id=2 bits_offset=0", 81 + "[7] UNION '(anon)' size=4 vlen=1\n" 82 + "\t'f1' type_id=1 bits_offset=0", 83 + "[8] ENUM 'e1' encoding=UNSIGNED size=4 vlen=1\n" 84 + "\t'v1' val=1", 85 + "[9] ENUM '(anon)' encoding=UNSIGNED size=4 vlen=1\n" 86 + "\t'av1' val=2", 87 + "[10] ENUM64 'e641' encoding=SIGNED size=8 vlen=1\n" 88 + "\t'v1' val=1024", 89 + "[11] ENUM64 '(anon)' encoding=SIGNED size=8 vlen=1\n" 90 + "\t'v1' val=1025", 91 + "[12] STRUCT 'unneeded' size=4 vlen=1\n" 92 + "\t'f1' type_id=1 bits_offset=0", 93 + "[13] STRUCT 'embedded' size=4 vlen=1\n" 94 + "\t'f1' type_id=1 bits_offset=0", 95 + "[14] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n" 96 + "\t'p1' type_id=1", 97 + "[15] ARRAY '(anon)' type_id=1 index_type_id=1 nr_elems=3", 98 + "[16] STRUCT 'from_proto' size=4 vlen=1\n" 99 + "\t'f1' type_id=1 bits_offset=0", 100 + "[17] UNION 'u1' size=4 vlen=1\n" 101 + "\t'f1' type_id=1 bits_offset=0"); 102 + 103 + btf2 = btf__new_empty_split(btf1); 104 + if (!ASSERT_OK_PTR(btf2, "empty_split_btf")) 105 + goto cleanup; 106 + 107 + btf__add_ptr(btf2, 3); /* [18] ptr to struct s1 */ 108 + /* add ptr to struct anon */ 109 + btf__add_ptr(btf2, 4); /* [19] ptr to struct (anon) */ 110 + btf__add_const(btf2, 6); /* [20] const union u1 */ 111 + btf__add_restrict(btf2, 7); /* [21] restrict union (anon) */ 112 + btf__add_volatile(btf2, 8); /* [22] volatile enum e1 */ 113 + btf__add_typedef(btf2, "et", 9); /* [23] typedef enum (anon) */ 114 + btf__add_const(btf2, 10); /* [24] const enum64 e641 */ 115 + btf__add_ptr(btf2, 11); /* [25] restrict enum64 (anon) */ 116 + btf__add_struct(btf2, "with_embedded", 4); /* [26] struct with_embedded { */ 117 + btf__add_field(btf2, "f1", 13, 0, 0); /* struct embedded f1; */ 118 + /* } */ 119 + btf__add_func(btf2, "fn", BTF_FUNC_STATIC, 14); /* [27] int fn(int p1); */ 120 + btf__add_typedef(btf2, "arraytype", 15); /* [28] typedef int[3] foo; */ 121 + btf__add_func_proto(btf2, 1); /* [29] int (*)(struct from proto p1); */ 122 + btf__add_func_param(btf2, "p1", 16); 123 + 124 + VALIDATE_RAW_BTF( 125 + btf2, 126 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 127 + "[2] PTR '(anon)' type_id=1", 128 + "[3] STRUCT 's1' size=8 vlen=1\n" 129 + "\t'f1' type_id=2 bits_offset=0", 130 + "[4] STRUCT '(anon)' size=12 vlen=2\n" 131 + "\t'f1' type_id=1 bits_offset=0\n" 132 + "\t'f2' type_id=3 bits_offset=32", 133 + "[5] INT 'unsigned int' size=4 bits_offset=0 nr_bits=32 encoding=(none)", 134 + "[6] UNION 'u1' size=12 vlen=2\n" 135 + "\t'f1' type_id=1 bits_offset=0\n" 136 + "\t'f2' type_id=2 bits_offset=0", 137 + "[7] UNION '(anon)' size=4 vlen=1\n" 138 + "\t'f1' type_id=1 bits_offset=0", 139 + "[8] ENUM 'e1' encoding=UNSIGNED size=4 vlen=1\n" 140 + "\t'v1' val=1", 141 + "[9] ENUM '(anon)' encoding=UNSIGNED size=4 vlen=1\n" 142 + "\t'av1' val=2", 143 + "[10] ENUM64 'e641' encoding=SIGNED size=8 vlen=1\n" 144 + "\t'v1' val=1024", 145 + "[11] ENUM64 '(anon)' encoding=SIGNED size=8 vlen=1\n" 146 + "\t'v1' val=1025", 147 + "[12] STRUCT 'unneeded' size=4 vlen=1\n" 148 + "\t'f1' type_id=1 bits_offset=0", 149 + "[13] STRUCT 'embedded' size=4 vlen=1\n" 150 + "\t'f1' type_id=1 bits_offset=0", 151 + "[14] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n" 152 + "\t'p1' type_id=1", 153 + "[15] ARRAY '(anon)' type_id=1 index_type_id=1 nr_elems=3", 154 + "[16] STRUCT 'from_proto' size=4 vlen=1\n" 155 + "\t'f1' type_id=1 bits_offset=0", 156 + "[17] UNION 'u1' size=4 vlen=1\n" 157 + "\t'f1' type_id=1 bits_offset=0", 158 + "[18] PTR '(anon)' type_id=3", 159 + "[19] PTR '(anon)' type_id=4", 160 + "[20] CONST '(anon)' type_id=6", 161 + "[21] RESTRICT '(anon)' type_id=7", 162 + "[22] VOLATILE '(anon)' type_id=8", 163 + "[23] TYPEDEF 'et' type_id=9", 164 + "[24] CONST '(anon)' type_id=10", 165 + "[25] PTR '(anon)' type_id=11", 166 + "[26] STRUCT 'with_embedded' size=4 vlen=1\n" 167 + "\t'f1' type_id=13 bits_offset=0", 168 + "[27] FUNC 'fn' type_id=14 linkage=static", 169 + "[28] TYPEDEF 'arraytype' type_id=15", 170 + "[29] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n" 171 + "\t'p1' type_id=16"); 172 + 173 + if (!ASSERT_EQ(0, btf__distill_base(btf2, &btf3, &btf4), 174 + "distilled_base") || 175 + !ASSERT_OK_PTR(btf3, "distilled_base") || 176 + !ASSERT_OK_PTR(btf4, "distilled_split") || 177 + !ASSERT_EQ(8, btf__type_cnt(btf3), "distilled_base_type_cnt")) 178 + goto cleanup; 179 + 180 + VALIDATE_RAW_BTF( 181 + btf4, 182 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 183 + "[2] STRUCT 's1' size=8 vlen=0", 184 + "[3] UNION 'u1' size=12 vlen=0", 185 + "[4] ENUM 'e1' encoding=UNSIGNED size=4 vlen=0", 186 + "[5] ENUM 'e641' encoding=UNSIGNED size=8 vlen=0", 187 + "[6] STRUCT 'embedded' size=4 vlen=0", 188 + "[7] STRUCT 'from_proto' size=4 vlen=0", 189 + /* split BTF; these types should match split BTF above from 17-28, with 190 + * updated type id references 191 + */ 192 + "[8] PTR '(anon)' type_id=2", 193 + "[9] PTR '(anon)' type_id=20", 194 + "[10] CONST '(anon)' type_id=3", 195 + "[11] RESTRICT '(anon)' type_id=21", 196 + "[12] VOLATILE '(anon)' type_id=4", 197 + "[13] TYPEDEF 'et' type_id=22", 198 + "[14] CONST '(anon)' type_id=5", 199 + "[15] PTR '(anon)' type_id=23", 200 + "[16] STRUCT 'with_embedded' size=4 vlen=1\n" 201 + "\t'f1' type_id=6 bits_offset=0", 202 + "[17] FUNC 'fn' type_id=24 linkage=static", 203 + "[18] TYPEDEF 'arraytype' type_id=25", 204 + "[19] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n" 205 + "\t'p1' type_id=7", 206 + /* split BTF types added from original base BTF below */ 207 + "[20] STRUCT '(anon)' size=12 vlen=2\n" 208 + "\t'f1' type_id=1 bits_offset=0\n" 209 + "\t'f2' type_id=2 bits_offset=32", 210 + "[21] UNION '(anon)' size=4 vlen=1\n" 211 + "\t'f1' type_id=1 bits_offset=0", 212 + "[22] ENUM '(anon)' encoding=UNSIGNED size=4 vlen=1\n" 213 + "\t'av1' val=2", 214 + "[23] ENUM64 '(anon)' encoding=SIGNED size=8 vlen=1\n" 215 + "\t'v1' val=1025", 216 + "[24] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n" 217 + "\t'p1' type_id=1", 218 + "[25] ARRAY '(anon)' type_id=1 index_type_id=1 nr_elems=3"); 219 + 220 + if (!ASSERT_EQ(btf__relocate(btf4, btf1), 0, "relocate_split")) 221 + goto cleanup; 222 + 223 + VALIDATE_RAW_BTF( 224 + btf4, 225 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 226 + "[2] PTR '(anon)' type_id=1", 227 + "[3] STRUCT 's1' size=8 vlen=1\n" 228 + "\t'f1' type_id=2 bits_offset=0", 229 + "[4] STRUCT '(anon)' size=12 vlen=2\n" 230 + "\t'f1' type_id=1 bits_offset=0\n" 231 + "\t'f2' type_id=3 bits_offset=32", 232 + "[5] INT 'unsigned int' size=4 bits_offset=0 nr_bits=32 encoding=(none)", 233 + "[6] UNION 'u1' size=12 vlen=2\n" 234 + "\t'f1' type_id=1 bits_offset=0\n" 235 + "\t'f2' type_id=2 bits_offset=0", 236 + "[7] UNION '(anon)' size=4 vlen=1\n" 237 + "\t'f1' type_id=1 bits_offset=0", 238 + "[8] ENUM 'e1' encoding=UNSIGNED size=4 vlen=1\n" 239 + "\t'v1' val=1", 240 + "[9] ENUM '(anon)' encoding=UNSIGNED size=4 vlen=1\n" 241 + "\t'av1' val=2", 242 + "[10] ENUM64 'e641' encoding=SIGNED size=8 vlen=1\n" 243 + "\t'v1' val=1024", 244 + "[11] ENUM64 '(anon)' encoding=SIGNED size=8 vlen=1\n" 245 + "\t'v1' val=1025", 246 + "[12] STRUCT 'unneeded' size=4 vlen=1\n" 247 + "\t'f1' type_id=1 bits_offset=0", 248 + "[13] STRUCT 'embedded' size=4 vlen=1\n" 249 + "\t'f1' type_id=1 bits_offset=0", 250 + "[14] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n" 251 + "\t'p1' type_id=1", 252 + "[15] ARRAY '(anon)' type_id=1 index_type_id=1 nr_elems=3", 253 + "[16] STRUCT 'from_proto' size=4 vlen=1\n" 254 + "\t'f1' type_id=1 bits_offset=0", 255 + "[17] UNION 'u1' size=4 vlen=1\n" 256 + "\t'f1' type_id=1 bits_offset=0", 257 + "[18] PTR '(anon)' type_id=3", 258 + "[19] PTR '(anon)' type_id=30", 259 + "[20] CONST '(anon)' type_id=6", 260 + "[21] RESTRICT '(anon)' type_id=31", 261 + "[22] VOLATILE '(anon)' type_id=8", 262 + "[23] TYPEDEF 'et' type_id=32", 263 + "[24] CONST '(anon)' type_id=10", 264 + "[25] PTR '(anon)' type_id=33", 265 + "[26] STRUCT 'with_embedded' size=4 vlen=1\n" 266 + "\t'f1' type_id=13 bits_offset=0", 267 + "[27] FUNC 'fn' type_id=34 linkage=static", 268 + "[28] TYPEDEF 'arraytype' type_id=35", 269 + "[29] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n" 270 + "\t'p1' type_id=16", 271 + /* below here are (duplicate) anon base types added by distill 272 + * process to split BTF. 273 + */ 274 + "[30] STRUCT '(anon)' size=12 vlen=2\n" 275 + "\t'f1' type_id=1 bits_offset=0\n" 276 + "\t'f2' type_id=3 bits_offset=32", 277 + "[31] UNION '(anon)' size=4 vlen=1\n" 278 + "\t'f1' type_id=1 bits_offset=0", 279 + "[32] ENUM '(anon)' encoding=UNSIGNED size=4 vlen=1\n" 280 + "\t'av1' val=2", 281 + "[33] ENUM64 '(anon)' encoding=SIGNED size=8 vlen=1\n" 282 + "\t'v1' val=1025", 283 + "[34] FUNC_PROTO '(anon)' ret_type_id=1 vlen=1\n" 284 + "\t'p1' type_id=1", 285 + "[35] ARRAY '(anon)' type_id=1 index_type_id=1 nr_elems=3"); 286 + 287 + cleanup: 288 + btf__free(btf4); 289 + btf__free(btf3); 290 + btf__free(btf2); 291 + btf__free(btf1); 292 + } 293 + 294 + /* ensure we can cope with multiple types with the same name in 295 + * distilled base BTF. In this case because sizes are different, 296 + * we can still disambiguate them. 297 + */ 298 + static void test_distilled_base_multi(void) 299 + { 300 + struct btf *btf1 = NULL, *btf2 = NULL, *btf3 = NULL, *btf4 = NULL; 301 + 302 + btf1 = btf__new_empty(); 303 + if (!ASSERT_OK_PTR(btf1, "empty_main_btf")) 304 + return; 305 + btf__add_int(btf1, "int", 4, BTF_INT_SIGNED); /* [1] int */ 306 + btf__add_int(btf1, "int", 8, BTF_INT_SIGNED); /* [2] int */ 307 + VALIDATE_RAW_BTF( 308 + btf1, 309 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 310 + "[2] INT 'int' size=8 bits_offset=0 nr_bits=64 encoding=SIGNED"); 311 + btf2 = btf__new_empty_split(btf1); 312 + if (!ASSERT_OK_PTR(btf2, "empty_split_btf")) 313 + goto cleanup; 314 + btf__add_ptr(btf2, 1); 315 + btf__add_const(btf2, 2); 316 + VALIDATE_RAW_BTF( 317 + btf2, 318 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 319 + "[2] INT 'int' size=8 bits_offset=0 nr_bits=64 encoding=SIGNED", 320 + "[3] PTR '(anon)' type_id=1", 321 + "[4] CONST '(anon)' type_id=2"); 322 + if (!ASSERT_EQ(0, btf__distill_base(btf2, &btf3, &btf4), 323 + "distilled_base") || 324 + !ASSERT_OK_PTR(btf3, "distilled_base") || 325 + !ASSERT_OK_PTR(btf4, "distilled_split") || 326 + !ASSERT_EQ(3, btf__type_cnt(btf3), "distilled_base_type_cnt")) 327 + goto cleanup; 328 + VALIDATE_RAW_BTF( 329 + btf3, 330 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 331 + "[2] INT 'int' size=8 bits_offset=0 nr_bits=64 encoding=SIGNED"); 332 + if (!ASSERT_EQ(btf__relocate(btf4, btf1), 0, "relocate_split")) 333 + goto cleanup; 334 + 335 + VALIDATE_RAW_BTF( 336 + btf4, 337 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 338 + "[2] INT 'int' size=8 bits_offset=0 nr_bits=64 encoding=SIGNED", 339 + "[3] PTR '(anon)' type_id=1", 340 + "[4] CONST '(anon)' type_id=2"); 341 + 342 + cleanup: 343 + btf__free(btf4); 344 + btf__free(btf3); 345 + btf__free(btf2); 346 + btf__free(btf1); 347 + } 348 + 349 + /* If a needed type is not present in the base BTF we wish to relocate 350 + * with, btf__relocate() should error our. 351 + */ 352 + static void test_distilled_base_missing_err(void) 353 + { 354 + struct btf *btf1 = NULL, *btf2 = NULL, *btf3 = NULL, *btf4 = NULL, *btf5 = NULL; 355 + 356 + btf1 = btf__new_empty(); 357 + if (!ASSERT_OK_PTR(btf1, "empty_main_btf")) 358 + return; 359 + btf__add_int(btf1, "int", 4, BTF_INT_SIGNED); /* [1] int */ 360 + btf__add_int(btf1, "int", 8, BTF_INT_SIGNED); /* [2] int */ 361 + VALIDATE_RAW_BTF( 362 + btf1, 363 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 364 + "[2] INT 'int' size=8 bits_offset=0 nr_bits=64 encoding=SIGNED"); 365 + btf2 = btf__new_empty_split(btf1); 366 + if (!ASSERT_OK_PTR(btf2, "empty_split_btf")) 367 + goto cleanup; 368 + btf__add_ptr(btf2, 1); 369 + btf__add_const(btf2, 2); 370 + VALIDATE_RAW_BTF( 371 + btf2, 372 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 373 + "[2] INT 'int' size=8 bits_offset=0 nr_bits=64 encoding=SIGNED", 374 + "[3] PTR '(anon)' type_id=1", 375 + "[4] CONST '(anon)' type_id=2"); 376 + if (!ASSERT_EQ(0, btf__distill_base(btf2, &btf3, &btf4), 377 + "distilled_base") || 378 + !ASSERT_OK_PTR(btf3, "distilled_base") || 379 + !ASSERT_OK_PTR(btf4, "distilled_split") || 380 + !ASSERT_EQ(3, btf__type_cnt(btf3), "distilled_base_type_cnt")) 381 + goto cleanup; 382 + VALIDATE_RAW_BTF( 383 + btf3, 384 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 385 + "[2] INT 'int' size=8 bits_offset=0 nr_bits=64 encoding=SIGNED"); 386 + btf5 = btf__new_empty(); 387 + if (!ASSERT_OK_PTR(btf5, "empty_reloc_btf")) 388 + return; 389 + btf__add_int(btf5, "int", 4, BTF_INT_SIGNED); /* [1] int */ 390 + VALIDATE_RAW_BTF( 391 + btf5, 392 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED"); 393 + ASSERT_EQ(btf__relocate(btf4, btf5), -EINVAL, "relocate_split"); 394 + 395 + cleanup: 396 + btf__free(btf5); 397 + btf__free(btf4); 398 + btf__free(btf3); 399 + btf__free(btf2); 400 + btf__free(btf1); 401 + } 402 + 403 + /* With 2 types of same size in distilled base BTF, relocation should 404 + * fail as we have no means to choose between them. 405 + */ 406 + static void test_distilled_base_multi_err(void) 407 + { 408 + struct btf *btf1 = NULL, *btf2 = NULL, *btf3 = NULL, *btf4 = NULL; 409 + 410 + btf1 = btf__new_empty(); 411 + if (!ASSERT_OK_PTR(btf1, "empty_main_btf")) 412 + return; 413 + btf__add_int(btf1, "int", 4, BTF_INT_SIGNED); /* [1] int */ 414 + btf__add_int(btf1, "int", 4, BTF_INT_SIGNED); /* [2] int */ 415 + VALIDATE_RAW_BTF( 416 + btf1, 417 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 418 + "[2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED"); 419 + btf2 = btf__new_empty_split(btf1); 420 + if (!ASSERT_OK_PTR(btf2, "empty_split_btf")) 421 + goto cleanup; 422 + btf__add_ptr(btf2, 1); 423 + btf__add_const(btf2, 2); 424 + VALIDATE_RAW_BTF( 425 + btf2, 426 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 427 + "[2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 428 + "[3] PTR '(anon)' type_id=1", 429 + "[4] CONST '(anon)' type_id=2"); 430 + if (!ASSERT_EQ(0, btf__distill_base(btf2, &btf3, &btf4), 431 + "distilled_base") || 432 + !ASSERT_OK_PTR(btf3, "distilled_base") || 433 + !ASSERT_OK_PTR(btf4, "distilled_split") || 434 + !ASSERT_EQ(3, btf__type_cnt(btf3), "distilled_base_type_cnt")) 435 + goto cleanup; 436 + VALIDATE_RAW_BTF( 437 + btf3, 438 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 439 + "[2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED"); 440 + ASSERT_EQ(btf__relocate(btf4, btf1), -EINVAL, "relocate_split"); 441 + cleanup: 442 + btf__free(btf4); 443 + btf__free(btf3); 444 + btf__free(btf2); 445 + btf__free(btf1); 446 + } 447 + 448 + /* With 2 types of same size in base BTF, relocation should 449 + * fail as we have no means to choose between them. 450 + */ 451 + static void test_distilled_base_multi_err2(void) 452 + { 453 + struct btf *btf1 = NULL, *btf2 = NULL, *btf3 = NULL, *btf4 = NULL, *btf5 = NULL; 454 + 455 + btf1 = btf__new_empty(); 456 + if (!ASSERT_OK_PTR(btf1, "empty_main_btf")) 457 + return; 458 + btf__add_int(btf1, "int", 4, BTF_INT_SIGNED); /* [1] int */ 459 + VALIDATE_RAW_BTF( 460 + btf1, 461 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED"); 462 + btf2 = btf__new_empty_split(btf1); 463 + if (!ASSERT_OK_PTR(btf2, "empty_split_btf")) 464 + goto cleanup; 465 + btf__add_ptr(btf2, 1); 466 + VALIDATE_RAW_BTF( 467 + btf2, 468 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 469 + "[2] PTR '(anon)' type_id=1"); 470 + if (!ASSERT_EQ(0, btf__distill_base(btf2, &btf3, &btf4), 471 + "distilled_base") || 472 + !ASSERT_OK_PTR(btf3, "distilled_base") || 473 + !ASSERT_OK_PTR(btf4, "distilled_split") || 474 + !ASSERT_EQ(2, btf__type_cnt(btf3), "distilled_base_type_cnt")) 475 + goto cleanup; 476 + VALIDATE_RAW_BTF( 477 + btf3, 478 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED"); 479 + btf5 = btf__new_empty(); 480 + if (!ASSERT_OK_PTR(btf5, "empty_reloc_btf")) 481 + return; 482 + btf__add_int(btf5, "int", 4, BTF_INT_SIGNED); /* [1] int */ 483 + btf__add_int(btf5, "int", 4, BTF_INT_SIGNED); /* [2] int */ 484 + VALIDATE_RAW_BTF( 485 + btf5, 486 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 487 + "[2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED"); 488 + ASSERT_EQ(btf__relocate(btf4, btf5), -EINVAL, "relocate_split"); 489 + cleanup: 490 + btf__free(btf5); 491 + btf__free(btf4); 492 + btf__free(btf3); 493 + btf__free(btf2); 494 + btf__free(btf1); 495 + } 496 + 497 + /* create split reference BTF from vmlinux + split BTF with a few type references; 498 + * ensure the resultant split reference BTF is as expected, containing only types 499 + * needed to disambiguate references from split BTF. 500 + */ 501 + static void test_distilled_base_vmlinux(void) 502 + { 503 + struct btf *split_btf = NULL, *vmlinux_btf = btf__load_vmlinux_btf(); 504 + struct btf *split_dist = NULL, *base_dist = NULL; 505 + __s32 int_id, myint_id; 506 + 507 + if (!ASSERT_OK_PTR(vmlinux_btf, "load_vmlinux")) 508 + return; 509 + int_id = btf__find_by_name_kind(vmlinux_btf, "int", BTF_KIND_INT); 510 + if (!ASSERT_GT(int_id, 0, "find_int")) 511 + goto cleanup; 512 + split_btf = btf__new_empty_split(vmlinux_btf); 513 + if (!ASSERT_OK_PTR(split_btf, "new_split")) 514 + goto cleanup; 515 + myint_id = btf__add_typedef(split_btf, "myint", int_id); 516 + btf__add_ptr(split_btf, myint_id); 517 + 518 + if (!ASSERT_EQ(btf__distill_base(split_btf, &base_dist, &split_dist), 0, 519 + "distill_vmlinux_base")) 520 + goto cleanup; 521 + 522 + if (!ASSERT_OK_PTR(split_dist, "split_distilled") || 523 + !ASSERT_OK_PTR(base_dist, "base_dist")) 524 + goto cleanup; 525 + VALIDATE_RAW_BTF( 526 + split_dist, 527 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 528 + "[2] TYPEDEF 'myint' type_id=1", 529 + "[3] PTR '(anon)' type_id=2"); 530 + 531 + cleanup: 532 + btf__free(split_dist); 533 + btf__free(base_dist); 534 + btf__free(split_btf); 535 + btf__free(vmlinux_btf); 536 + } 537 + 538 + void test_btf_distill(void) 539 + { 540 + if (test__start_subtest("distilled_base")) 541 + test_distilled_base(); 542 + if (test__start_subtest("distilled_base_multi")) 543 + test_distilled_base_multi(); 544 + if (test__start_subtest("distilled_base_missing_err")) 545 + test_distilled_base_missing_err(); 546 + if (test__start_subtest("distilled_base_multi_err")) 547 + test_distilled_base_multi_err(); 548 + if (test__start_subtest("distilled_base_multi_err2")) 549 + test_distilled_base_multi_err2(); 550 + if (test__start_subtest("distilled_base_vmlinux")) 551 + test_distilled_base_vmlinux(); 552 + }