[PATCH bpf-next 2/3] bpf: Introduce BTF_SET/ID_SUB and BPF_VERIF_KFUNC_DEF

From: Chengkaitao

Date: Fri Apr 03 2026 - 13:14:39 EST


From: Kaitao Cheng <chengkaitao@xxxxxxxxxx>

Use BTF_SET_SUB to provide the same kind of grouping as BTF_SET_START/END,
so BTF_ID_SUB no longer has to follow the strict sequence (BTF_SET_START,
BTF_ID, BTF_SET_END). That lets us scatter BTF_ID_SUB definitions across
the file and collect entries with similar properties together, which
reduces maintenance overhead.

Signed-off-by: Kaitao Cheng <chengkaitao@xxxxxxxxxx>
---
include/linux/btf_ids.h | 92 +++++++++++++++++++++++++++++++----
tools/include/linux/btf_ids.h | 83 +++++++++++++++++++++++++++----
2 files changed, 156 insertions(+), 19 deletions(-)

diff --git a/include/linux/btf_ids.h b/include/linux/btf_ids.h
index af011db39ab3..c45275c88649 100644
--- a/include/linux/btf_ids.h
+++ b/include/linux/btf_ids.h
@@ -40,9 +40,9 @@ struct btf_id_set8 {

#define BTF_IDS_SECTION ".BTF_ids"

-#define ____BTF_ID(symbol, word) \
+#define ____BTF_ID(symbol, word, sec) \
asm( \
-".pushsection " BTF_IDS_SECTION ",\"a\"; \n" \
+".pushsection " sec ",\"a\"; \n" \
".local " #symbol " ; \n" \
".type " #symbol ", STT_OBJECT; \n" \
".size " #symbol ", 4; \n" \
@@ -52,7 +52,7 @@ word \
".popsection; \n");

#define __BTF_ID(symbol, word) \
- ____BTF_ID(symbol, word)
+ ____BTF_ID(symbol, word, BTF_IDS_SECTION)

#define __ID(prefix) \
__PASTE(__PASTE(prefix, __COUNTER__), __LINE__)
@@ -86,19 +86,19 @@ word \
* .zero 4
*
*/
-#define __BTF_ID_LIST(name, scope) \
+#define __BTF_ID_LIST(name, scope, sec) \
asm( \
-".pushsection " BTF_IDS_SECTION ",\"a\"; \n" \
+".pushsection " sec ",\"a\"; \n" \
"." #scope " " #name "; \n" \
#name ":; \n" \
".popsection; \n");

#define BTF_ID_LIST(name) \
-__BTF_ID_LIST(name, local) \
+__BTF_ID_LIST(name, local, BTF_IDS_SECTION) \
extern u32 name[];

#define BTF_ID_LIST_GLOBAL(name, n) \
-__BTF_ID_LIST(name, globl)
+__BTF_ID_LIST(name, globl, BTF_IDS_SECTION)

/* The BTF_ID_LIST_SINGLE macro defines a BTF_ID_LIST with
* a single entry.
@@ -154,11 +154,11 @@ asm( \
".popsection; \n");

#define BTF_SET_START(name) \
-__BTF_ID_LIST(name, local) \
+__BTF_ID_LIST(name, local, BTF_IDS_SECTION) \
__BTF_SET_START(name, local)

#define BTF_SET_START_GLOBAL(name) \
-__BTF_ID_LIST(name, globl) \
+__BTF_ID_LIST(name, globl, BTF_IDS_SECTION) \
__BTF_SET_START(name, globl)

#define BTF_SET_END(name) \
@@ -168,6 +168,75 @@ asm( \
".popsection; \n"); \
extern struct btf_id_set name;

+/*
+ * BTF_SET_SUB — place a set in .BTF_ids.<name> so vmlinux.lds.h can merge
+ * multiple input sections into one output .BTF_ids in a fixed order.
+ * <name> must be a single preprocessor token (e.g. bpf_verif_kfunc_arena).
+ *
+ * Member count: begin is __BTF_ID__setsc__<name> (first in .BTF_ids.<name>);
+ * end is linker symbol __BTF_ids_seg_end_<name> (see btf_ids.lds.h). resolve_btfids
+ * uses cnt = (end - begin) / 4 - 1. <name> must not contain "__seg__".
+ *
+ * extern struct btf_id_set name is emitted by BTF_SET_SUB. BTF_ID_SUB(name, ...)
+ * must use the same <name> as the subsection token.
+ */
+#define __BTF_IDS_SUBSEC(sub) ".BTF_ids." #sub
+
+/* Indirection so __ID() expands before ____BTF_ID() stringifies its symbol arg. */
+#define __BTF_ID_SUB(sym, sec) ____BTF_ID(sym, "", sec)
+
+#define BTF_ID_SUB(sub, prefix, name) \
+ __BTF_ID_SUB(__ID(__BTF_ID__##prefix##__##name##__), __BTF_IDS_SUBSEC(sub))
+
+#define __BTF_ID_LIST_SUB(name, scope) \
+ __BTF_ID_LIST(name, scope, __BTF_IDS_SUBSEC(name))
+
+#define __BTF_SET_SUB(name, scope) \
+asm( \
+".pushsection " __BTF_IDS_SUBSEC(name) ",\"a\"; \n" \
+"." #scope " __BTF_ID__setsc__" #name "; \n" \
+"__BTF_ID__setsc__" #name ":; \n" \
+".zero 4 \n" \
+".popsection; \n");
+
+#define BTF_SET_SUB(name) \
+extern struct btf_id_set name; \
+__BTF_ID_LIST_SUB(name, local) \
+__BTF_SET_SUB(name, local)
+
+#include <linux/args.h> /* CONCATENATE, COUNT_ARGS */
+
+/* bpf_verif_kfunc_<sub> (e.g. rbtree_add → bpf_verif_kfunc_rbtree_add) */
+#define __BPF_VERIF_KFUNC_SUB(sub) bpf_verif_kfunc_##sub
+
+/* Cascade: emit first subsection, recurse on the rest (same kfunc @name). Up to 6 subs. */
+#define __BPF_VERIF_KFUNC_DEF_1(name, s1) \
+ BTF_ID_SUB(__BPF_VERIF_KFUNC_SUB(s1), func, name)
+
+#define __BPF_VERIF_KFUNC_DEF_2(name, s1, s2) \
+ BTF_ID_SUB(__BPF_VERIF_KFUNC_SUB(s1), func, name) \
+ __BPF_VERIF_KFUNC_DEF_1(name, s2)
+
+#define __BPF_VERIF_KFUNC_DEF_3(name, s1, s2, s3) \
+ BTF_ID_SUB(__BPF_VERIF_KFUNC_SUB(s1), func, name) \
+ __BPF_VERIF_KFUNC_DEF_2(name, s2, s3)
+
+#define __BPF_VERIF_KFUNC_DEF_4(name, s1, s2, s3, s4) \
+ BTF_ID_SUB(__BPF_VERIF_KFUNC_SUB(s1), func, name) \
+ __BPF_VERIF_KFUNC_DEF_3(name, s2, s3, s4)
+
+#define __BPF_VERIF_KFUNC_DEF_5(name, s1, s2, s3, s4, s5) \
+ BTF_ID_SUB(__BPF_VERIF_KFUNC_SUB(s1), func, name) \
+ __BPF_VERIF_KFUNC_DEF_4(name, s2, s3, s4, s5)
+
+#define __BPF_VERIF_KFUNC_DEF_6(name, s1, s2, s3, s4, s5, s6) \
+ BTF_ID_SUB(__BPF_VERIF_KFUNC_SUB(s1), func, name) \
+ __BPF_VERIF_KFUNC_DEF_5(name, s2, s3, s4, s5, s6)
+
+/* First arg: kfunc symbol; rest: subsection suffix tokens matching bpf_verif_kfunc_<s>. */
+#define BPF_VERIF_KFUNC_DEF(name, ...) \
+ CONCATENATE(__BPF_VERIF_KFUNC_DEF_, COUNT_ARGS(__VA_ARGS__))(name, __VA_ARGS__)
+
/*
* The BTF_SET8_START/END macros pair defines sorted list of
* BTF IDs and their flags plus its members count, with the
@@ -190,7 +259,7 @@ extern struct btf_id_set name;
*
*/
#define __BTF_SET8_START(name, scope, flags) \
-__BTF_ID_LIST(name, local) \
+__BTF_ID_LIST(name, local, BTF_IDS_SECTION) \
asm( \
".pushsection " BTF_IDS_SECTION ",\"a\"; \n" \
"." #scope " __BTF_ID__set8__" #name "; \n" \
@@ -227,6 +296,9 @@ BTF_SET8_END(name)
#define BTF_SET_START(name) static struct btf_id_set __maybe_unused name = { 0 };
#define BTF_SET_START_GLOBAL(name) static struct btf_id_set __maybe_unused name = { 0 };
#define BTF_SET_END(name)
+#define BTF_SET_SUB(name) static struct btf_id_set __maybe_unused name = { 0 };
+#define BTF_ID_SUB(sub, prefix, name)
+#define BPF_VERIF_KFUNC_DEF(name, ...)
#define BTF_SET8_START(name) static struct btf_id_set8 __maybe_unused name = { 0 };
#define BTF_SET8_END(name)
#define BTF_KFUNCS_START(name) static struct btf_id_set8 __maybe_unused name = { .flags = BTF_SET8_KFUNCS };
diff --git a/tools/include/linux/btf_ids.h b/tools/include/linux/btf_ids.h
index 72ea363d434d..026fd5bfc6d5 100644
--- a/tools/include/linux/btf_ids.h
+++ b/tools/include/linux/btf_ids.h
@@ -35,9 +35,9 @@ struct btf_id_set8 {

#define BTF_IDS_SECTION ".BTF_ids"

-#define ____BTF_ID(symbol) \
+#define ____BTF_ID(symbol, sec) \
asm( \
-".pushsection " BTF_IDS_SECTION ",\"a\"; \n" \
+".pushsection " sec ",\"a\"; \n" \
".local " #symbol " ; \n" \
".type " #symbol ", STT_OBJECT; \n" \
".size " #symbol ", 4; \n" \
@@ -46,7 +46,7 @@ asm( \
".popsection; \n");

#define __BTF_ID(symbol) \
- ____BTF_ID(symbol)
+ ____BTF_ID(symbol, BTF_IDS_SECTION)

#define __ID(prefix) \
__PASTE(__PASTE(prefix, __COUNTER__), __LINE__)
@@ -73,19 +73,19 @@ asm( \
* .zero 4
*
*/
-#define __BTF_ID_LIST(name, scope) \
+#define __BTF_ID_LIST(name, scope, sec) \
asm( \
-".pushsection " BTF_IDS_SECTION ",\"a\"; \n" \
+".pushsection " sec ",\"a\"; \n" \
"." #scope " " #name "; \n" \
#name ":; \n" \
".popsection; \n");

#define BTF_ID_LIST(name) \
-__BTF_ID_LIST(name, local) \
+__BTF_ID_LIST(name, local, BTF_IDS_SECTION) \
extern u32 name[];

#define BTF_ID_LIST_GLOBAL(name, n) \
-__BTF_ID_LIST(name, globl)
+__BTF_ID_LIST(name, globl, BTF_IDS_SECTION)

/* The BTF_ID_LIST_SINGLE macro defines a BTF_ID_LIST with
* a single entry.
@@ -141,11 +141,11 @@ asm( \
".popsection; \n");

#define BTF_SET_START(name) \
-__BTF_ID_LIST(name, local) \
+__BTF_ID_LIST(name, local, BTF_IDS_SECTION) \
__BTF_SET_START(name, local)

#define BTF_SET_START_GLOBAL(name) \
-__BTF_ID_LIST(name, globl) \
+__BTF_ID_LIST(name, globl, BTF_IDS_SECTION) \
__BTF_SET_START(name, globl)

#define BTF_SET_END(name) \
@@ -155,6 +155,68 @@ asm( \
".popsection; \n"); \
extern struct btf_id_set name;

+/*
+ * See include/linux/btf_ids.h: BTF_SET_SUB uses __BTF_ids_seg_end_<name> in
+ * btf_ids.lds.h; begin is __BTF_ID__setsc__<name>. extern struct btf_id_set name
+ * is in BTF_SET_SUB.
+ */
+#define __BTF_IDS_SUBSEC(sub) ".BTF_ids." #sub
+
+/* Indirection so __ID() expands before ____BTF_ID() stringifies its symbol arg. */
+#define __BTF_ID_SUB(sym, sec) ____BTF_ID(sym, sec)
+
+#define BTF_ID_SUB(sub, prefix, name) \
+ __BTF_ID_SUB(__ID(__BTF_ID__##prefix##__##name##__), __BTF_IDS_SUBSEC(sub))
+
+#define __BTF_ID_LIST_SUB(name, scope) \
+ __BTF_ID_LIST(name, scope, __BTF_IDS_SUBSEC(name))
+
+#define __BTF_SET_SUB(name, scope) \
+asm( \
+".pushsection " __BTF_IDS_SUBSEC(name) ",\"a\"; \n" \
+"." #scope " __BTF_ID__setsc__" #name "; \n" \
+"__BTF_ID__setsc__" #name ":; \n" \
+".zero 4 \n" \
+".popsection; \n");
+
+#define BTF_SET_SUB(name) \
+extern struct btf_id_set name; \
+__BTF_ID_LIST_SUB(name, local) \
+__BTF_SET_SUB(name, local)
+
+#include <linux/args.h> /* CONCATENATE, COUNT_ARGS */
+
+/* bpf_verif_kfunc_<sub> (e.g. rbtree_add → bpf_verif_kfunc_rbtree_add) */
+#define __BPF_VERIF_KFUNC_SUB(sub) bpf_verif_kfunc_##sub
+
+/* Cascade: emit first subsection, recurse on the rest (same kfunc @name). Up to 6 subs. */
+#define __BPF_VERIF_KFUNC_DEF_1(name, s1) \
+ BTF_ID_SUB(__BPF_VERIF_KFUNC_SUB(s1), func, name)
+
+#define __BPF_VERIF_KFUNC_DEF_2(name, s1, s2) \
+ BTF_ID_SUB(__BPF_VERIF_KFUNC_SUB(s1), func, name) \
+ __BPF_VERIF_KFUNC_DEF_1(name, s2)
+
+#define __BPF_VERIF_KFUNC_DEF_3(name, s1, s2, s3) \
+ BTF_ID_SUB(__BPF_VERIF_KFUNC_SUB(s1), func, name) \
+ __BPF_VERIF_KFUNC_DEF_2(name, s2, s3)
+
+#define __BPF_VERIF_KFUNC_DEF_4(name, s1, s2, s3, s4) \
+ BTF_ID_SUB(__BPF_VERIF_KFUNC_SUB(s1), func, name) \
+ __BPF_VERIF_KFUNC_DEF_3(name, s2, s3, s4)
+
+#define __BPF_VERIF_KFUNC_DEF_5(name, s1, s2, s3, s4, s5) \
+ BTF_ID_SUB(__BPF_VERIF_KFUNC_SUB(s1), func, name) \
+ __BPF_VERIF_KFUNC_DEF_4(name, s2, s3, s4, s5)
+
+#define __BPF_VERIF_KFUNC_DEF_6(name, s1, s2, s3, s4, s5, s6) \
+ BTF_ID_SUB(__BPF_VERIF_KFUNC_SUB(s1), func, name) \
+ __BPF_VERIF_KFUNC_DEF_5(name, s2, s3, s4, s5, s6)
+
+/* First arg: kfunc symbol; rest: subsection suffix tokens matching bpf_verif_kfunc_<s>. */
+#define BPF_VERIF_KFUNC_DEF(name, ...) \
+ CONCATENATE(__BPF_VERIF_KFUNC_DEF_, COUNT_ARGS(__VA_ARGS__))(name, __VA_ARGS__)
+
#else

#define BTF_ID_LIST(name) static u32 __maybe_unused name[5];
@@ -166,6 +228,9 @@ extern struct btf_id_set name;
#define BTF_SET_START(name) static struct btf_id_set __maybe_unused name = { 0 };
#define BTF_SET_START_GLOBAL(name) static struct btf_id_set __maybe_unused name = { 0 };
#define BTF_SET_END(name)
+#define BTF_SET_SUB(name) static struct btf_id_set __maybe_unused name = { 0 };
+#define BTF_ID_SUB(sub, prefix, name)
+#define BPF_VERIF_KFUNC_DEF(name, ...)

#endif /* CONFIG_DEBUG_INFO_BTF */

--
2.43.0