On 2/3/24 19:48, Manu Bretelle wrote: > On Fri, Feb 02, 2024 at 06:38:18PM -0700, Daniel Xu wrote: >> Hi Viktor, >> >> On Wed, Jan 31, 2024 at 05:24:09PM +0100, Viktor Malik wrote: >>> The .BTF_ids section is pre-filled with zeroed BTF ID entries during the >>> build and afterwards patched by resolve_btfids with correct values. >>> Since resolve_btfids always writes in host-native endianness, it relies >>> on libelf to do the translation when the target ELF is cross-compiled to >>> a different endianness (this was introduced in commit 61e8aeda9398 >>> ("bpf: Fix libelf endian handling in resolv_btfids")). >>> >>> Unfortunately, the translation will corrupt the flags fields of SET8 >>> entries because these were written during vmlinux compilation and are in >>> the correct endianness already. This will lead to numerous selftests >>> failures such as: >>> >>> $ sudo ./test_verifier 502 502 >>> #502/p sleepable fentry accept FAIL >>> Failed to load prog 'Invalid argument'! >>> bpf_fentry_test1 is not sleepable >>> verification time 34 usec >>> stack depth 0 >>> processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0 >>> Summary: 0 PASSED, 0 SKIPPED, 1 FAILED >>> >>> Since it's not possible to instruct libelf to translate just certain >>> values, let's manually bswap the flags in resolve_btfids when needed, so >>> that libelf then translates everything correctly. >>> >>> Fixes: ef2c6f370a63 ("tools/resolve_btfids: Add support for 8-byte BTF sets") >>> Signed-off-by: Viktor Malik <vmalik@xxxxxxxxxx> >>> --- >>> tools/bpf/resolve_btfids/main.c | 27 ++++++++++++++++++++++++++- >>> 1 file changed, 26 insertions(+), 1 deletion(-) >>> >>> diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c >>> index 7badf1557e5c..d01603ef6283 100644 >>> --- a/tools/bpf/resolve_btfids/main.c >>> +++ b/tools/bpf/resolve_btfids/main.c >>> @@ -652,13 +652,23 @@ static int sets_patch(struct object *obj) >>> Elf_Data *data = obj->efile.idlist; >>> int *ptr = data->d_buf; >>> struct rb_node *next; >>> + GElf_Ehdr ehdr; >>> + int need_bswap; >>> + >>> + if (gelf_getehdr(obj->efile.elf, &ehdr) == NULL) { >>> + pr_err("FAILED cannot get ELF header: %s\n", >>> + elf_errmsg(-1)); >>> + return -1; >>> + } >>> + need_bswap = (__BYTE_ORDER == __LITTLE_ENDIAN) != >>> + (ehdr.e_ident[EI_DATA] == ELFDATA2LSB); >>> >>> next = rb_first(&obj->sets); >>> while (next) { >>> unsigned long addr, idx; >>> struct btf_id *id; >>> void *base; >>> - int cnt, size; >>> + int cnt, size, i; >>> >>> id = rb_entry(next, struct btf_id, rb_node); >>> addr = id->addr[0]; >>> @@ -686,6 +696,21 @@ static int sets_patch(struct object *obj) >>> base = set8->pairs; >>> cnt = set8->cnt; >>> size = sizeof(set8->pairs[0]); >>> + >>> + /* >>> + * When ELF endianness does not match endianness of the >>> + * host, libelf will do the translation when updating >>> + * the ELF. This, however, corrupts SET8 flags which are >>> + * already in the target endianness. So, let's bswap >>> + * them to the host endianness and libelf will then >>> + * correctly translate everything. >>> + */ >>> + if (need_bswap) { >>> + for (i = 0; i < cnt; i++) { >>> + set8->pairs[i].flags = >>> + bswap_32(set8->pairs[i].flags); >>> + } >> >> Do we need this for btf_id_set8:flags as well? Didn't get a chance to >> look too deeply yet. >> >> Thanks, >> Daniel > > I ran some test and tried and validated Jiri's patch in > https://lore.kernel.org/bpf/Zb6Jt30bNcNhM6zR@surya/ Right, I'll include that patch. Thanks for testing! Viktor > > Manu >