Skip to content

Commit

Permalink
tools/resolve_btfids: Fix cross-compilation to non-host endianness
Browse files Browse the repository at this point in the history
[ Upstream commit 903fad4 ]

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 61e8aed
("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 (both global and entry flags) in
resolve_btfids when needed, so that libelf then translates everything
correctly.

Fixes: ef2c6f3 ("tools/resolve_btfids: Add support for 8-byte BTF sets")
Signed-off-by: Viktor Malik <vmalik@redhat.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/7b6bff690919555574ce0f13d2a5996cacf7bf69.1707223196.git.vmalik@redhat.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Viktor Malik authored and Sasha Levin committed Mar 26, 2024
1 parent 29d1ee8 commit e4c4a02
Showing 1 changed file with 35 additions and 0 deletions.
35 changes: 35 additions & 0 deletions tools/bpf/resolve_btfids/main.c
Expand Up @@ -90,6 +90,14 @@

#define ADDR_CNT 100

#if __BYTE_ORDER == __LITTLE_ENDIAN
# define ELFDATANATIVE ELFDATA2LSB
#elif __BYTE_ORDER == __BIG_ENDIAN
# define ELFDATANATIVE ELFDATA2MSB
#else
# error "Unknown machine endianness!"
#endif

struct btf_id {
struct rb_node rb_node;
char *name;
Expand Down Expand Up @@ -117,6 +125,7 @@ struct object {
int idlist_shndx;
size_t strtabidx;
unsigned long idlist_addr;
int encoding;
} efile;

struct rb_root sets;
Expand Down Expand Up @@ -320,6 +329,7 @@ static int elf_collect(struct object *obj)
{
Elf_Scn *scn = NULL;
size_t shdrstrndx;
GElf_Ehdr ehdr;
int idx = 0;
Elf *elf;
int fd;
Expand Down Expand Up @@ -351,6 +361,13 @@ static int elf_collect(struct object *obj)
return -1;
}

if (gelf_getehdr(obj->efile.elf, &ehdr) == NULL) {
pr_err("FAILED cannot get ELF header: %s\n",
elf_errmsg(-1));
return -1;
}
obj->efile.encoding = ehdr.e_ident[EI_DATA];

/*
* Scan all the elf sections and look for save data
* from .BTF_ids section and symbols.
Expand Down Expand Up @@ -681,6 +698,24 @@ static int sets_patch(struct object *obj)
*/
BUILD_BUG_ON(set8->pairs != &set8->pairs[0].id);
qsort(set8->pairs, set8->cnt, sizeof(set8->pairs[0]), cmp_id);

/*
* 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 (obj->efile.encoding != ELFDATANATIVE) {
int i;

set8->flags = bswap_32(set8->flags);
for (i = 0; i < set8->cnt; i++) {
set8->pairs[i].flags =
bswap_32(set8->pairs[i].flags);
}
}
}

pr_debug("sorting addr %5lu: cnt %6d [%s]\n",
Expand Down

0 comments on commit e4c4a02

Please sign in to comment.