mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 15:22:21 -04:00
tracing/boot: Add support for eprobe, fprobe, and tprobe events
Boot-time tracing currently supports kprobe-events and synthetic-events under per-event configuration options. Extend boot-time tracing to support newly added dynamic probe types: - event probes (eprobe) under the "eprobes" event group - function probes (fprobe) under the "fprobes" event group - tracepoint probes (tprobe) under the "tracepoints" or "tprobes" event group To support this cleanly, update dyn_event_create() in trace_dynevent.c so that passing NULL as the type parameter delegates to create_dyn_event(), allowing generic creation of any registered dynamic event type from a raw command string. Update Documentation/trace/boottime-trace.rst accordingly to describe the new per-event bootconfig options. Link: https://lore.kernel.org/all/178613905149.259829.18185480460810689421.stgit@devnote2/ Assisted-by: Antigravity:gemini-3.6-flash Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Changes in v3: - Check return values of strscpy() and snprintf() in trace_boot_add_probe_event() to prevent silent buffer truncation when constructing probe event strings. Changes in v2: - Fix raw command detection logic for eprobes, fprobes, and tprobes by requiring ':' or isspace() after type prefix. - Consolidate duplicate loop logic into trace_boot_add_probe_event() helper function.
This commit is contained in:
@@ -121,9 +121,21 @@ ftrace.[instance.INSTANCE.]event.synthetic.EVENT.fields = FIELD[, FIELD2[...]]
|
||||
Defines new synthetic event with FIELDs. Each field should be
|
||||
"type varname".
|
||||
|
||||
Note that kprobe and synthetic event definitions can be written under
|
||||
instance node, but those are also visible from other instances. So please
|
||||
take care for event name conflict.
|
||||
ftrace.[instance.INSTANCE.]event.eprobes.EVENT.probes = PROBE[, PROBE2[...]]
|
||||
Defines new event probe based on PROBEs. This option is available only
|
||||
for the event which group name is "eprobes".
|
||||
|
||||
ftrace.[instance.INSTANCE.]event.fprobes.EVENT.probes = PROBE[, PROBE2[...]]
|
||||
Defines new fprobe event based on PROBEs. This option is available only
|
||||
for the event which group name is "fprobes".
|
||||
|
||||
ftrace.[instance.INSTANCE.]event.tracepoints.EVENT.probes = PROBE[, PROBE2[...]]
|
||||
Defines new tracepoint probe based on PROBEs. This option is available only
|
||||
for the event which group name is "tracepoints" or "tprobes".
|
||||
|
||||
Note that dynamic event definitions can be written under instance node, but
|
||||
those are also visible from other instances. So please take care for event
|
||||
name conflict.
|
||||
|
||||
Ftrace Histogram Options
|
||||
------------------------
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/trace_events.h>
|
||||
|
||||
#include "trace.h"
|
||||
#include "trace_dynevent.h"
|
||||
|
||||
#define MAX_BUF_LEN 256
|
||||
|
||||
@@ -172,6 +173,93 @@ trace_boot_add_synth_event(struct xbc_node *node, const char *event)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_EPROBE_EVENTS) || defined(CONFIG_FPROBE_EVENTS)
|
||||
static int __init
|
||||
trace_boot_add_probe_event(struct xbc_node *node, const char *group,
|
||||
const char *event, char type, const char *type_name)
|
||||
{
|
||||
struct xbc_node *anode;
|
||||
char buf[MAX_BUF_LEN];
|
||||
const char *val;
|
||||
int ret = 0;
|
||||
|
||||
xbc_node_for_each_array_value(node, "probes", anode, val) {
|
||||
if (val[0] == type && (val[1] == ':' || isspace(val[1]))) {
|
||||
ret = strscpy(buf, val, MAX_BUF_LEN);
|
||||
if (ret < 0) {
|
||||
pr_err("%s command is too long: %s\n", type_name, val);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ret = snprintf(buf, MAX_BUF_LEN, "%c:%s/%s %s", type, group, event, val);
|
||||
if (ret >= MAX_BUF_LEN || ret < 0) {
|
||||
pr_err("%s command is too long: %c:%s/%s %s\n",
|
||||
type_name, type, group, event, val);
|
||||
ret = -E2BIG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = dyn_event_create(buf, NULL);
|
||||
if (ret) {
|
||||
pr_err("Failed to add %s: %s\n", type_name, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EPROBE_EVENTS
|
||||
static inline int __init
|
||||
trace_boot_add_eprobe_event(struct xbc_node *node, const char *group,
|
||||
const char *event)
|
||||
{
|
||||
return trace_boot_add_probe_event(node, group, event, 'e', "eprobe");
|
||||
}
|
||||
#else
|
||||
static inline int __init
|
||||
trace_boot_add_eprobe_event(struct xbc_node *node, const char *group,
|
||||
const char *event)
|
||||
{
|
||||
pr_err("Event probe is not supported.\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FPROBE_EVENTS
|
||||
static inline int __init
|
||||
trace_boot_add_fprobe_event(struct xbc_node *node, const char *group,
|
||||
const char *event)
|
||||
{
|
||||
return trace_boot_add_probe_event(node, group, event, 'f', "fprobe");
|
||||
}
|
||||
|
||||
static inline int __init
|
||||
trace_boot_add_tprobe_event(struct xbc_node *node, const char *group,
|
||||
const char *event)
|
||||
{
|
||||
return trace_boot_add_probe_event(node, group, event, 't', "tprobe");
|
||||
}
|
||||
#else
|
||||
static inline int __init
|
||||
trace_boot_add_fprobe_event(struct xbc_node *node, const char *group,
|
||||
const char *event)
|
||||
{
|
||||
pr_err("Fprobe event is not supported.\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int __init
|
||||
trace_boot_add_tprobe_event(struct xbc_node *node, const char *group,
|
||||
const char *event)
|
||||
{
|
||||
pr_err("Tracepoint probe is not supported.\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HIST_TRIGGERS
|
||||
static int __init __printf(3, 4)
|
||||
append_printf(char **bufp, char *end, const char *fmt, ...)
|
||||
@@ -477,6 +565,15 @@ trace_boot_init_one_event(struct trace_array *tr, struct xbc_node *gnode,
|
||||
if (!strcmp(group, "synthetic"))
|
||||
if (trace_boot_add_synth_event(enode, event) < 0)
|
||||
return;
|
||||
if (!strcmp(group, "eprobes"))
|
||||
if (trace_boot_add_eprobe_event(enode, group, event) < 0)
|
||||
return;
|
||||
if (!strcmp(group, "fprobes"))
|
||||
if (trace_boot_add_fprobe_event(enode, group, event) < 0)
|
||||
return;
|
||||
if (!strcmp(group, "tracepoints") || !strcmp(group, "tprobes"))
|
||||
if (trace_boot_add_tprobe_event(enode, group, event) < 0)
|
||||
return;
|
||||
|
||||
mutex_lock(&event_mutex);
|
||||
file = find_event_file(tr, group, event);
|
||||
|
||||
@@ -116,6 +116,8 @@ int dyn_event_release(const char *raw_command, struct dyn_event_operations *type
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int create_dyn_event(const char *raw_command);
|
||||
|
||||
/*
|
||||
* Locked version of event creation. The event creation must be protected by
|
||||
* dyn_event_ops_mutex because of protecting trace_probe_log.
|
||||
@@ -124,6 +126,9 @@ int dyn_event_create(const char *raw_command, struct dyn_event_operations *type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!type)
|
||||
return create_dyn_event(raw_command);
|
||||
|
||||
mutex_lock(&dyn_event_ops_mutex);
|
||||
ret = type->create(raw_command);
|
||||
mutex_unlock(&dyn_event_ops_mutex);
|
||||
|
||||
Reference in New Issue
Block a user