mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-27 19:53:15 -04:00
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>
This commit is contained in:
committed by
Steven Rostedt
parent
f8c9b3051d
commit
eadc0725ab
@@ -298,6 +298,15 @@ struct trace_event_class {
|
||||
struct list_head *(*get_fields)(struct trace_event_call *);
|
||||
struct list_head fields;
|
||||
int (*raw_init)(struct trace_event_call *);
|
||||
#ifdef CONFIG_BPF_EVENTS
|
||||
/*
|
||||
* Per-template BTF ids set by DECLARE_EVENT_CLASS via BTF_ID() and
|
||||
* patched by resolve_btfids at link time. NULL for handcrafted classes.
|
||||
* [0] FUNC __bpf_trace_<template>
|
||||
* [1] STRUCT trace_event_raw_<template>
|
||||
*/
|
||||
const u32 *btf_ids;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern int trace_event_reg(struct trace_event_call *event,
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/trace_events.h>
|
||||
#include <linux/btf_ids.h>
|
||||
|
||||
#ifndef TRACE_SYSTEM_VAR
|
||||
#define TRACE_SYSTEM_VAR TRACE_SYSTEM
|
||||
@@ -397,6 +398,27 @@ static inline notrace int trace_event_get_offsets_##call( \
|
||||
#define _TRACE_PERF_INIT(call)
|
||||
#endif /* CONFIG_PERF_EVENTS */
|
||||
|
||||
#ifdef CONFIG_BPF_EVENTS
|
||||
/*
|
||||
* Per-template BTF id list, populated at link time by resolve_btfids:
|
||||
* [0] FUNC __bpf_trace_<call> (the BPF dispatcher)
|
||||
* [1] STRUCT trace_event_raw_<call> (the ring-buffer record)
|
||||
* Exposed via the events/<sys>/<name>/btf_ids tracefs file.
|
||||
*/
|
||||
#define _TRACE_BTF_IDS_DECLARE(call) \
|
||||
extern u32 __bpf_trace_btf_ids_##call[]; \
|
||||
BTF_ID_LIST_GLOBAL(__bpf_trace_btf_ids_##call, 2) \
|
||||
BTF_ID(func, __bpf_trace_##call) \
|
||||
BTF_ID(struct, trace_event_raw_##call)
|
||||
|
||||
#define _TRACE_BTF_IDS_INIT(call) \
|
||||
.btf_ids = __bpf_trace_btf_ids_##call,
|
||||
|
||||
#else
|
||||
#define _TRACE_BTF_IDS_DECLARE(call)
|
||||
#define _TRACE_BTF_IDS_INIT(call)
|
||||
#endif /* CONFIG_BPF_EVENTS */
|
||||
|
||||
#include "stages/stage6_event_callback.h"
|
||||
|
||||
|
||||
@@ -474,6 +496,7 @@ static inline void ftrace_test_probe_##call(void) \
|
||||
#undef DECLARE_EVENT_CLASS
|
||||
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
|
||||
_TRACE_PERF_PROTO(call, PARAMS(proto)); \
|
||||
_TRACE_BTF_IDS_DECLARE(call) \
|
||||
static char print_fmt_##call[] = print; \
|
||||
static struct trace_event_class __used __refdata event_class_##call = { \
|
||||
.system = TRACE_SYSTEM_STRING, \
|
||||
@@ -483,6 +506,7 @@ static struct trace_event_class __used __refdata event_class_##call = { \
|
||||
.probe = trace_event_raw_event_##call, \
|
||||
.reg = trace_event_reg, \
|
||||
_TRACE_PERF_INIT(call) \
|
||||
_TRACE_BTF_IDS_INIT(call) \
|
||||
};
|
||||
|
||||
#undef DECLARE_EVENT_SYSCALL_CLASS
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user