Skip to content

Commit 7491e2c

Browse files
tzstoyanovrostedt
authored andcommitted
tracing: Add a probe that attaches to trace events
A new dynamic event is introduced: event probe. The event is attached to an existing tracepoint and uses its fields as arguments. The user can specify custom format string of the new event, select what tracepoint arguments will be printed and how to print them. An event probe is created by writing configuration string in 'dynamic_events' ftrace file: e[:[SNAME/]ENAME] SYSTEM/EVENT [FETCHARGS] - Set an event probe -:SNAME/ENAME - Delete an event probe Where: SNAME - System name, if omitted 'eprobes' is used. ENAME - Name of the new event in SNAME, if omitted the SYSTEM_EVENT is used. SYSTEM - Name of the system, where the tracepoint is defined, mandatory. EVENT - Name of the tracepoint event in SYSTEM, mandatory. FETCHARGS - Arguments: <name>=$<field>[:TYPE] - Fetch given filed of the tracepoint and print it as given TYPE with given name. Supported types are: (u8/u16/u32/u64/s8/s16/s32/s64), basic type (x8/x16/x32/x64), hexadecimal types "string", "ustring" and bitfield. Example, attach an event probe on openat system call and print name of the file that will be opened: echo "e:esys/eopen syscalls/sys_enter_openat file=\$filename:string" >> dynamic_events A new dynamic event is created in events/esys/eopen/ directory. It can be deleted with: echo "-:esys/eopen" >> dynamic_events Filters, triggers and histograms can be attached to the new event, it can be matched in synthetic events. There is one limitation - an event probe can not be attached to kprobe, uprobe or another event probe. Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Acked-by: Masami Hiramatsu <[email protected]> Co-developed-by: Steven Rostedt (VMware) <[email protected]> Signed-off-by: Tzvetomir Stoyanov (VMware) <[email protected]> Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent 8e24206 commit 7491e2c

File tree

9 files changed

+962
-13
lines changed

9 files changed

+962
-13
lines changed

include/linux/trace_events.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ enum {
313313
TRACE_EVENT_FL_DYNAMIC_BIT,
314314
TRACE_EVENT_FL_KPROBE_BIT,
315315
TRACE_EVENT_FL_UPROBE_BIT,
316+
TRACE_EVENT_FL_EPROBE_BIT,
316317
};
317318

318319
/*
@@ -325,6 +326,7 @@ enum {
325326
* DYNAMIC - Event is a dynamic event (created at run time)
326327
* KPROBE - Event is a kprobe
327328
* UPROBE - Event is a uprobe
329+
* EPROBE - Event is an event probe
328330
*/
329331
enum {
330332
TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT),
@@ -335,6 +337,7 @@ enum {
335337
TRACE_EVENT_FL_DYNAMIC = (1 << TRACE_EVENT_FL_DYNAMIC_BIT),
336338
TRACE_EVENT_FL_KPROBE = (1 << TRACE_EVENT_FL_KPROBE_BIT),
337339
TRACE_EVENT_FL_UPROBE = (1 << TRACE_EVENT_FL_UPROBE_BIT),
340+
TRACE_EVENT_FL_EPROBE = (1 << TRACE_EVENT_FL_EPROBE_BIT),
338341
};
339342

340343
#define TRACE_EVENT_FL_UKPROBE (TRACE_EVENT_FL_KPROBE | TRACE_EVENT_FL_UPROBE)
@@ -680,6 +683,7 @@ enum event_trigger_type {
680683
ETT_EVENT_ENABLE = (1 << 3),
681684
ETT_EVENT_HIST = (1 << 4),
682685
ETT_HIST_ENABLE = (1 << 5),
686+
ETT_EVENT_EPROBE = (1 << 6),
683687
};
684688

685689
extern int filter_match_preds(struct event_filter *filter, void *rec);

kernel/trace/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ obj-$(CONFIG_EVENT_TRACING) += trace_event_perf.o
7777
endif
7878
obj-$(CONFIG_EVENT_TRACING) += trace_events_filter.o
7979
obj-$(CONFIG_EVENT_TRACING) += trace_events_trigger.o
80+
obj-$(CONFIG_PROBE_EVENTS) += trace_eprobe.o
8081
obj-$(CONFIG_TRACE_EVENT_INJECT) += trace_events_inject.o
8182
obj-$(CONFIG_SYNTH_EVENTS) += trace_events_synth.o
8283
obj-$(CONFIG_HIST_TRIGGERS) += trace_events_hist.o

kernel/trace/trace.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5543,6 +5543,7 @@ static const char readme_msg[] =
55435543
#ifdef CONFIG_HIST_TRIGGERS
55445544
"\t s:[synthetic/]<event> <field> [<field>]\n"
55455545
#endif
5546+
"\t e[:[<group>/]<event>] <attached-group>.<attached-event> [<args>]\n"
55465547
"\t -:[<group>/]<event>\n"
55475548
#ifdef CONFIG_KPROBE_EVENTS
55485549
"\t place: [<module>:]<symbol>[+<offset>]|<memaddr>\n"
@@ -5552,7 +5553,7 @@ static const char readme_msg[] =
55525553
" place (uprobe): <path>:<offset>[%return][(ref_ctr_offset)]\n"
55535554
#endif
55545555
"\t args: <name>=fetcharg[:type]\n"
5555-
"\t fetcharg: %<register>, @<address>, @<symbol>[+|-<offset>],\n"
5556+
"\t fetcharg: (%<register>|$<efield>), @<address>, @<symbol>[+|-<offset>],\n"
55565557
#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
55575558
"\t $stack<index>, $stack, $retval, $comm, $arg<N>,\n"
55585559
#else
@@ -5567,6 +5568,8 @@ static const char readme_msg[] =
55675568
"\t stype: u8/u16/u32/u64, s8/s16/s32/s64, pid_t,\n"
55685569
"\t [unsigned] char/int/long\n"
55695570
#endif
5571+
"\t efield: For event probes ('e' types), the field is on of the fields\n"
5572+
"\t of the <attached-group>/<attached-event>.\n"
55705573
#endif
55715574
" events/\t\t- Directory containing all trace event subsystems:\n"
55725575
" enable\t\t- Write 0/1 to enable/disable tracing of all events\n"

kernel/trace/trace.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ struct kprobe_trace_entry_head {
126126
unsigned long ip;
127127
};
128128

129+
struct eprobe_trace_entry_head {
130+
struct trace_entry ent;
131+
unsigned int type;
132+
};
133+
129134
struct kretprobe_trace_entry_head {
130135
struct trace_entry ent;
131136
unsigned long func;
@@ -1508,9 +1513,14 @@ static inline int register_trigger_hist_enable_disable_cmds(void) { return 0; }
15081513
extern int register_trigger_cmds(void);
15091514
extern void clear_event_triggers(struct trace_array *tr);
15101515

1516+
enum {
1517+
EVENT_TRIGGER_FL_PROBE = BIT(0),
1518+
};
1519+
15111520
struct event_trigger_data {
15121521
unsigned long count;
15131522
int ref;
1523+
int flags;
15141524
struct event_trigger_ops *ops;
15151525
struct event_command *cmd_ops;
15161526
struct event_filter __rcu *filter;
@@ -1918,6 +1928,14 @@ static inline bool is_good_name(const char *name)
19181928
return true;
19191929
}
19201930

1931+
/* Convert certain expected symbols into '_' when generating event names */
1932+
static inline void sanitize_event_name(char *name)
1933+
{
1934+
while (*name++ != '\0')
1935+
if (*name == ':' || *name == '.')
1936+
*name = '_';
1937+
}
1938+
19211939
/*
19221940
* This is a generic way to read and write a u64 value from a file in tracefs.
19231941
*

0 commit comments

Comments
 (0)