libbpf: Handle non-standardly sized enums better in BTF-to-C dumper
Turns out C allows to force enum to be 1-byte or 8-byte explicitly using mode(byte) or mode(word), respecticely. Linux sources are using this in some cases. This is imporant to handle correctly, as enum size determines corresponding fields in a struct that use that enum type. And if enum size is incorrect, this will lead to invalid struct layout. So add mode(byte) and mode(word) attribute support to btf_dump APIs. Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://lore.kernel.org/bpf/20221212211505.558851-3-andrii@kernel.org
This commit is contained in:
parent
872aec4b5f
commit
21a9a1bccc
@ -13,6 +13,7 @@
|
||||
#include <ctype.h>
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -1076,6 +1077,43 @@ static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
|
||||
else
|
||||
btf_dump_emit_enum64_val(d, t, lvl, vlen);
|
||||
btf_dump_printf(d, "\n%s}", pfx(lvl));
|
||||
|
||||
/* special case enums with special sizes */
|
||||
if (t->size == 1) {
|
||||
/* one-byte enums can be forced with mode(byte) attribute */
|
||||
btf_dump_printf(d, " __attribute__((mode(byte)))");
|
||||
} else if (t->size == 8 && d->ptr_sz == 8) {
|
||||
/* enum can be 8-byte sized if one of the enumerator values
|
||||
* doesn't fit in 32-bit integer, or by adding mode(word)
|
||||
* attribute (but probably only on 64-bit architectures); do
|
||||
* our best here to try to satisfy the contract without adding
|
||||
* unnecessary attributes
|
||||
*/
|
||||
bool needs_word_mode;
|
||||
|
||||
if (btf_is_enum(t)) {
|
||||
/* enum can't represent 64-bit values, so we need word mode */
|
||||
needs_word_mode = true;
|
||||
} else {
|
||||
/* enum64 needs mode(word) if none of its values has
|
||||
* non-zero upper 32-bits (which means that all values
|
||||
* fit in 32-bit integers and won't cause compiler to
|
||||
* bump enum to be 64-bit naturally
|
||||
*/
|
||||
int i;
|
||||
|
||||
needs_word_mode = true;
|
||||
for (i = 0; i < vlen; i++) {
|
||||
if (btf_enum64(t)[i].val_hi32 != 0) {
|
||||
needs_word_mode = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needs_word_mode)
|
||||
btf_dump_printf(d, " __attribute__((mode(word)))");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
|
||||
|
Loading…
x
Reference in New Issue
Block a user