* [PATCH bpf-next] libbpf: Match unsigned enum values when dumping data
@ 2026-10-31 23:32 Hungyu Lin
2026-11-01 0:22 ` Alexei Starovoitov
0 siblings, 1 reply; 2+ messages in thread
From: Hungyu Lin @ 2026-10-31 23:32 UTC (permalink / raw)
To: andrii, bpf; +Cc: ast, daniel, yonghong.song, linux-kernel, Hungyu Lin
btf_dump_get_enum_value() zero-extends unsigned 32-bit enum data, but
btf_dump_enum_data() compares it with the signed enumerator field.
Known values with bit 31 set therefore fail to match and are printed
numerically. For example, HIGH = 0x80000000U is dumped as
"(enum flags)2147483648" instead of "(enum flags)HIGH".
Extend the enumerator according to the enum's signedness before
comparing it with the data value. Keep the signed arm at 64 bits so
negative enumerators are not converted to unsigned by the conditional
operator.
Fixes: d90ec262b35b ("libbpf: Add enum64 support for btf_dump")
Signed-off-by: Hungyu Lin <dennylin0707@gmail.com>
---
tools/lib/bpf/btf_dump.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
index ea9a34db4c00..7608179aa0f0 100644
--- a/tools/lib/bpf/btf_dump.c
+++ b/tools/lib/bpf/btf_dump.c
@@ -2373,7 +2373,7 @@ static int btf_dump_enum_data(struct btf_dump *d,
const struct btf_enum *e;
for (i = 0, e = btf_enum(t); i < btf_vlen(t); i++, e++) {
- if (value != e->val)
+ if (value != (is_signed ? (__s64)e->val : (__u32)e->val))
continue;
btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
return 0;
base-commit: eaae576c34d7e001767b6845a5950b0b8db3e68a
--
2.43.0
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH bpf-next] libbpf: Match unsigned enum values when dumping data
2026-10-31 23:32 [PATCH bpf-next] libbpf: Match unsigned enum values when dumping data Hungyu Lin
@ 2026-11-01 0:22 ` Alexei Starovoitov
0 siblings, 0 replies; 2+ messages in thread
From: Alexei Starovoitov @ 2026-11-01 0:22 UTC (permalink / raw)
To: Hungyu Lin, andrii, bpf; +Cc: daniel, yonghong.song, linux-kernel
On Sat, Oct 31, 2026 at 04:32 PM Hungyu Lin <dennylin0707@gmail.com> wrote:
> @@ -2373,7 +2373,7 @@ static int btf_dump_enum_data(struct btf_dump *d,
> - if (value != e->val)
> + if (value != (is_signed ? (__s64)e->val : (__u32)e->val))
This is the third patch in two days about the sign of BTF enum values.
btf_enum->val is __s32 for unsigned enums too.
libbpf widens it to 64 bits in three places and ignores kflag in
all three:
function val = 0x80000000, kflag = 0
---------------------------- ----------------------------------
btf_dump_enum_data() no match, prints 2147483648
get_map_field_long() map_extra = 0xffffffff80000000
bpf_core_calc_enumval_relo() *val = 0xffffffff80000000
__ulong(map_extra, 0x80000000) gets to the second one.
The arena cannot be mmap-ed at that address.
When the same mistake is made in N places the interface is the problem.
Lets add a helper next to btf_enum64_value(). bpftool can use it too.
The diff leaves bpf_core_calc_enumval_relo() alone.
Pls check what clang puts into ld_imm64 for such enumerator.
Pls send libbpf, bpftool and the selftest as one series.
Something like this
diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
index 57f1263..d6a770c 100644
--- a/tools/lib/bpf/btf.h
+++ b/tools/lib/bpf/btf.h
@@ -636,6 +636,12 @@ static inline struct btf_enum *btf_enum(const struct btf_type *t)
return (struct btf_enum *)(t + 1);
}
+/* btf_enum->val is __s32 for unsigned enums too. kflag of the enum has the sign. */
+static inline __s64 btf_enum_value(const struct btf_type *t, const struct btf_enum *e)
+{
+ return btf_kflag(t) ? (__s64)e->val : (__u32)e->val;
+}
+
struct btf_enum64;
static inline struct btf_enum64 *btf_enum64(const struct btf_type *t)
diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c
index ea9a34d..37c9c4a 100644
--- a/tools/lib/bpf/btf_dump.c
+++ b/tools/lib/bpf/btf_dump.c
@@ -2373,7 +2373,7 @@ static int btf_dump_enum_data(struct btf_dump *d,
const struct btf_enum *e;
for (i = 0, e = btf_enum(t); i < btf_vlen(t); i++, e++) {
- if (value != e->val)
+ if (value != btf_enum_value(t, e))
continue;
btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
return 0;
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 02e75b1..cecd6b5 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -2627,7 +2627,7 @@ static bool get_map_field_long(const char *map_name, const struct btf *btf,
if (btf_is_enum(t)) {
const struct btf_enum *e = btf_enum(t);
- *res = e->val;
+ *res = btf_enum_value(t, e);
} else {
const struct btf_enum64 *e = btf_enum64(t);
diff --git a/tools/testing/selftests/bpf/prog_tests/btf_dump.c b/tools/testing/selftests/bpf/prog_tests/btf_dump.c
index dbef014..f3d165a 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf_dump.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf_dump.c
@@ -919,6 +919,9 @@ static void test_btf_dump_typedef_data(struct btf *btf, struct btf_dump *d,
static void test_btf_dump_enum_data(struct btf *btf, struct btf_dump *d,
char *str)
{
+ __u32 high = 0x80000000;
+ __s32 neg = -1;
+
/* enum where enum value does (and does not) exist */
TEST_BTF_DUMP_DATA_C(btf, d, "enum", str, enum bpf_cmd, BTF_F_COMPACT,
BPF_MAP_CREATE);
@@ -950,6 +953,22 @@ static void test_btf_dump_enum_data(struct btf *btf, struct btf_dump *d,
TEST_BTF_DUMP_DATA_OVER(btf, d, "enum", str, enum bpf_cmd,
sizeof(enum bpf_cmd) - 1, "", BPF_MAP_CREATE);
+
+ /* enumerators with bit 31 set in unsigned and in signed enum */
+ ASSERT_GT(btf__add_enum(btf, "test_enum_u32", 4), 0, "add unsigned enum");
+ ASSERT_OK(btf__add_enum_value(btf, "TEST_ENUM_HIGH", 0x80000000), "add TEST_ENUM_HIGH");
+ ASSERT_GT(btf__add_enum(btf, "test_enum_s32", 4), 0, "add signed enum");
+ ASSERT_OK(btf__add_enum_value(btf, "TEST_ENUM_NEG", -1), "add TEST_ENUM_NEG");
+
+ /* btf_dump__dump_type_data() doesn't resize 'd' for the new types */
+ d = btf_dump__new(btf, btf_dump_snprintf, str, NULL);
+ if (!ASSERT_OK_PTR(d, "btf_dump__new"))
+ return;
+ ASSERT_OK(btf_dump_data(btf, d, "test_enum_u32", NULL, 0, &high, 4, str,
+ "(enum test_enum_u32)TEST_ENUM_HIGH"), "dump unsigned enum");
+ ASSERT_OK(btf_dump_data(btf, d, "test_enum_s32", NULL, 0, &neg, 4, str,
+ "(enum test_enum_s32)TEST_ENUM_NEG"), "dump signed enum");
+ btf_dump__free(d);
}
static void test_btf_dump_struct_data(struct btf *btf, struct btf_dump *d,
pw-bot: cr
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-01 0:22 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-31 23:32 [PATCH bpf-next] libbpf: Match unsigned enum values when dumping data Hungyu Lin
2026-11-01 0:22 ` Alexei Starovoitov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®