summaryrefslogtreecommitdiff
path: root/kernel/trace
diff options
context:
space:
mode:
authorMykyta Yatsenko <yatsenko@meta.com>2026-05-18 08:23:16 -0700
committerSteven Rostedt <rostedt@goodmis.org>2026-07-28 07:18:48 -0400
commiteadc0725ab8d38c05148fce49f8d5c6a0e01f062 (patch)
tree2ca91ce64b7c929e6cf9f593a16e988ba4cfe4a9 /kernel/trace
parentf8c9b3051ded5a397172aee79271cc46529ca8f2 (diff)
downloadlinux-next-eadc0725ab8d38c05148fce49f8d5c6a0e01f062.tar.gz
linux-next-eadc0725ab8d38c05148fce49f8d5c6a0e01f062.zip
tracing: Expose tracepoint BTF ids via tracefs
Add events/<sys>/<event>/btf_ids, a per-template file that exposes the BTF ids resolve_btfids fills in for each tracepoint: btf_obj_id BTF object owning the ids below raw_btf_id FUNC_PROTO of __bpf_trace_<call> (named args), consumed by raw_tp / tp_btf BPF programs tp_btf_id trace_event_raw_<call> ring-buffer record, consumed by classic BPF_PROG_TYPE_TRACEPOINT programs DECLARE_EVENT_CLASS now emits a 2-entry BTF_ID_LIST (FUNC __bpf_trace_* and STRUCT trace_event_raw_*) and stores the pointer in trace_event_class. Per-syscall events under syscalls/ share the handcrafted classes event_class_syscall_{enter,exit} instead of going through DECLARE_EVENT_CLASS. Wire those classes to the BTF id lists generated for sys_enter / sys_exit so all ~700 per-syscall events expose the shared dispatcher prototype and record. The per-syscall events do not own their own tracepoint (they share sys_enter/sys_exit), so raw_btf_id is reported as 0 on those events; the meaningful raw_btf_id is exposed on raw_syscalls/sys_{enter,exit}/btf_ids where raw_tp / tp_btf programs can actually attach. Link: https://patch.msgid.link/20260518-generic_tracepoint-v2-2-b755a5cf67bb@meta.com Signed-off-by: Mykyta Yatsenko <yatsenko@meta.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace_events.c80
-rw-r--r--kernel/trace/trace_syscalls.c17
2 files changed, 96 insertions, 1 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 956692856fa8..e0449e648871 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -22,6 +22,7 @@
#include <linux/sort.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/btf.h>
#include <trace/events/sched.h>
#include <trace/syscall.h>
@@ -2202,6 +2203,61 @@ event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
}
#endif
+#ifdef CONFIG_BPF_EVENTS
+static ssize_t
+event_btf_ids_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ struct trace_event_file *file;
+ struct trace_event_call *call;
+ const struct btf_type *t;
+ struct module *mod = NULL;
+ u32 raw_id = 0, tp_id = 0, obj_id = 0;
+ const u32 *ids;
+ struct btf *btf;
+ char buf[128];
+ int len;
+
+ /* Module unload could free call->class and ids[] mid-read. */
+ scoped_guard(mutex, &event_mutex) {
+ file = event_file_file(filp);
+ if (!file)
+ return -ENODEV;
+
+ call = file->event_call;
+ ids = call->class->btf_ids;
+ if (!ids)
+ return -ENOENT;
+ if (!(call->flags & TRACE_EVENT_FL_DYNAMIC))
+ mod = (struct module *)call->module;
+
+ btf = btf_get_module_btf(mod);
+ if (IS_ERR_OR_NULL(btf))
+ return -ENOENT;
+
+ /* Module-local ids in ids[] need base+local relocation. */
+ tp_id = btf_relocate_id(btf, ids[1]);
+
+ /*
+ * Without FL_TRACEPOINT the dispatcher is shared (e.g. all
+ * per-syscall events fan out from __bpf_trace_sys_enter), so
+ * raw_btf_id has no per-event attach point — report 0.
+ */
+ if (call->flags & TRACE_EVENT_FL_TRACEPOINT) {
+ t = btf_type_by_id(btf, btf_relocate_id(btf, ids[0]));
+ raw_id = t ? t->type : 0;
+ }
+ obj_id = btf_obj_id(btf);
+ btf_put(btf);
+ }
+
+ len = scnprintf(buf, sizeof(buf),
+ "btf_obj_id: %u\nraw_btf_id: %u\ntp_btf_id: %u\n",
+ obj_id, raw_id, tp_id);
+
+ return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
+}
+#endif
+
static ssize_t
event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
loff_t *ppos)
@@ -2702,6 +2758,13 @@ static const struct file_operations ftrace_event_id_fops = {
};
#endif
+#ifdef CONFIG_BPF_EVENTS
+static const struct file_operations ftrace_event_btf_ids_fops = {
+ .read = event_btf_ids_read,
+ .llseek = default_llseek,
+};
+#endif
+
static const struct file_operations ftrace_event_filter_fops = {
.open = tracing_open_file_tr,
.read = event_filter_read,
@@ -3095,6 +3158,14 @@ static int event_callback(const char *name, umode_t *mode, void **data,
}
#endif
+#ifdef CONFIG_BPF_EVENTS
+ if (call->class->btf_ids && strcmp(name, "btf_ids") == 0) {
+ *mode = TRACE_MODE_READ;
+ *fops = &ftrace_event_btf_ids_fops;
+ return 1;
+ }
+#endif
+
#ifdef CONFIG_HIST_TRIGGERS
if (strcmp(name, "hist") == 0) {
*mode = TRACE_MODE_READ;
@@ -3149,7 +3220,14 @@ event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file)
.callback = event_callback,
},
#endif
-#define NR_RO_EVENT_ENTRIES (1 + IS_ENABLED(CONFIG_PERF_EVENTS))
+#ifdef CONFIG_BPF_EVENTS
+ {
+ .name = "btf_ids",
+ .callback = event_callback,
+ },
+#endif
+#define NR_RO_EVENT_ENTRIES (1 + IS_ENABLED(CONFIG_PERF_EVENTS) + \
+ IS_ENABLED(CONFIG_BPF_EVENTS))
/* Readonly files must be above this line and counted by NR_RO_EVENT_ENTRIES. */
{
.name = "enable",
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 8a4f3c75e39f..48ef1a93e576 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -1303,12 +1303,26 @@ struct trace_event_functions exit_syscall_print_funcs = {
.trace = print_syscall_exit,
};
+#ifdef CONFIG_BPF_EVENTS
+/*
+ * BTF id lists generated by DECLARE_EVENT_CLASS for the sys_enter and
+ * sys_exit tracepoints. The auto-generated event_class_sys_{enter,exit}
+ * is unused (per-syscall events share the handcrafted classes below),
+ * but the id lists themselves are global and reusable.
+ */
+extern u32 __bpf_trace_btf_ids_sys_enter[];
+extern u32 __bpf_trace_btf_ids_sys_exit[];
+#endif
+
struct trace_event_class __refdata event_class_syscall_enter = {
.system = "syscalls",
.reg = syscall_enter_register,
.fields_array = syscall_enter_fields_array,
.get_fields = syscall_get_enter_fields,
.raw_init = init_syscall_trace,
+#ifdef CONFIG_BPF_EVENTS
+ .btf_ids = __bpf_trace_btf_ids_sys_enter,
+#endif
};
struct trace_event_class __refdata event_class_syscall_exit = {
@@ -1321,6 +1335,9 @@ struct trace_event_class __refdata event_class_syscall_exit = {
},
.fields = LIST_HEAD_INIT(event_class_syscall_exit.fields),
.raw_init = init_syscall_trace,
+#ifdef CONFIG_BPF_EVENTS
+ .btf_ids = __bpf_trace_btf_ids_sys_exit,
+#endif
};
unsigned long __init __weak arch_syscall_addr(int nr)