BPF and other consumers that want to attach to or decode a generic
tracepoint need three pieces of BTF information for it:
- the BTF of the object that owns the tracepoint's types
- the FUNC_PROTO describing the tracepoint arguments (with names),
consumed by raw_tp / tp_btf BPF programs
- the STRUCT id of trace_event_raw_<call>, the ring-buffer record
consumed by classic BPF_PROG_TYPE_TRACEPOINT programs
Today none of this is easily discoverable from userspace. The kernel
knows the ids - resolve_btfids fills them in at link time - but
consumers have to search them by the naming convention
("__bpf_trace_<name>", "trace_event_raw_<name>"), walking BTF for
every tracepoint.
This series stores those ids in trace_event_class and exposes them
via events/<sys>/<event>/btf_ids, e.g.
# cat /sys/kernel/tracing/events/sched/sched_switch/btf_ids
btf_obj_id: 1
raw_btf_id: 28882
tp_btf_id: 106335
# bpftool btf dump id 1 root_id 28882 format raw
[28882] FUNC_PROTO '(anon)' ret_type_id=0 vlen=5
'__data' type_id=9
'preempt' type_id=60674
'prev' type_id=219
'next' type_id=219
'prev_state' type_id=108689
# bpftool btf dump id 1 root_id 106335 format raw
[106335] STRUCT 'trace_event_raw_sched_switch' size=64 vlen=9
'ent' type_id=104654 bits_offset=0
'prev_comm' type_id=580 bits_offset=64
'prev_pid' type_id=92875 bits_offset=192
'prev_prio' type_id=79365 bits_offset=224
'prev_state' type_id=83958 bits_offset=256
'next_comm' type_id=580 bits_offset=320
'next_pid' type_id=92875 bits_offset=448
'next_prio' type_id=79365 bits_offset=480
'__data' type_id=407 bits_offset=512
For per-syscall events (all sharing the same dispatcher), raw_btf_id
is 0 — raw_tp / tp_btf programs attach to raw_syscalls/sys_{enter,exit},
not per-syscall events:
# cat /sys/kernel/tracing/events/syscalls/sys_enter_write/btf_ids
btf_obj_id: 1
raw_btf_id: 0
tp_btf_id: 106540
This unlocks few usecases for consumers:
- Resolving tp_btf attach targets and argument types directly,
instead of constructing "__bpf_trace_*" names and
re-discovering them in vmlinux BTF.
- Get a stable, machine-readable contract for tracepoint payloads,
with field names preserved.
Patch 1 exports the two BTF helpers the tracing core needs.
Patch 2 wires DECLARE_EVENT_CLASS to publish the ids, adds the tracefs
reader, and wires the syscall classes so per-syscall events
carry tp_btf_id (raw_btf_id is 0 there — see above).
Patch 3 adds a selftest covering the sched_switch tracepoint.
Signed-off-by: Mykyta Yatsenko <[email protected]>
---
Changes in v2:
- kernel/bpf/btf.c: dropped both EXPORT_SYMBOL_GPL()
- kernel/trace/trace_events.c (event_btf_ids_read):
replaced guard(mutex)(&event_mutex) with explicit
mutex_lock/mutex_unlock. scnprintf() and simple_read_from_buffer()
(which calls copy_to_user()) now run outside the lock work.
- tools/testing/selftests/bpf/prog_tests/tp_btf_ids.c:
- Added if (!env.has_testmod) { test__skip(); return; } at the top of
test_tp_btf_ids() so the test skips gracefully when bpf_testmod.ko
is absent.
- Wrapped ASSERT_EQ(btf_vlen(proto_t), 3, ...) with if (!...) goto out;
to prevent OOB read of params[2].
- Added if (!ASSERT_GE(btf_vlen(rec_t), 5, ...)) goto out; before reading
members[0..4].
- Link to v1:
https://patch.msgid.link/[email protected]
---
Mykyta Yatsenko (3):
bpf: Make btf_get_module_btf() and btf_relocate_id() non-static
tracing: Expose tracepoint BTF ids via tracefs
selftests/bpf: Add test for tracepoint btf_ids tracefs file
include/linux/btf.h | 2 +
include/linux/trace_events.h | 9 ++
include/trace/trace_events.h | 24 ++++
kernel/bpf/btf.c | 4 +-
kernel/trace/trace_events.c | 80 ++++++++++++-
kernel/trace/trace_syscalls.c | 17 +++
.../testing/selftests/bpf/prog_tests/tp_btf_ids.c | 132 +++++++++++++++++++++
7 files changed, 265 insertions(+), 3 deletions(-)
---
base-commit: 8668cd470c38011c44a42f6c7b188f4149f23a7a
change-id: 20260508-generic_tracepoint-d488a5a7ab18
Best regards,
--
Mykyta Yatsenko <[email protected]>