Skip to content

Commit f3f096c

Browse files
srikardIngo Molnar
authored andcommitted
tracing: Provide trace events interface for uprobes
Implements trace_event support for uprobes. In its current form it can be used to put probes at a specified offset in a file and dump the required registers when the code flow reaches the probed address. The following example shows how to dump the instruction pointer and %ax a register at the probed text address. Here we are trying to probe zfree in /bin/zsh: # cd /sys/kernel/debug/tracing/ # cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp 00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh # objdump -T /bin/zsh | grep -w zfree 0000000000446420 g DF .text 0000000000000012 Base zfree # echo 'p /bin/zsh:0x46420 %ip %ax' > uprobe_events # cat uprobe_events p:uprobes/p_zsh_0x46420 /bin/zsh:0x0000000000046420 # echo 1 > events/uprobes/enable # sleep 20 # echo 0 > events/uprobes/enable # cat trace # tracer: nop # # TASK-PID CPU# TIMESTAMP FUNCTION # | | | | | zsh-24842 [006] 258544.995456: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 zsh-24842 [007] 258545.000270: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 zsh-24842 [002] 258545.043929: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 zsh-24842 [004] 258547.046129: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79 Signed-off-by: Srikar Dronamraju <[email protected]> Acked-by: Steven Rostedt <[email protected]> Acked-by: Masami Hiramatsu <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Ananth N Mavinakayanahalli <[email protected]> Cc: Jim Keniston <[email protected]> Cc: Linux-mm <[email protected]> Cc: Oleg Nesterov <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Anton Arapov <[email protected]> Cc: Peter Zijlstra <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 8ab83f5 commit f3f096c

File tree

9 files changed

+919
-7
lines changed

9 files changed

+919
-7
lines changed

Documentation/trace/uprobetracer.txt

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
Uprobe-tracer: Uprobe-based Event Tracing
2+
=========================================
3+
Documentation written by Srikar Dronamraju
4+
5+
Overview
6+
--------
7+
Uprobe based trace events are similar to kprobe based trace events.
8+
To enable this feature, build your kernel with CONFIG_UPROBE_EVENTS=y.
9+
10+
Similar to the kprobe-event tracer, this doesn't need to be activated via
11+
current_tracer. Instead of that, add probe points via
12+
/sys/kernel/debug/tracing/uprobe_events, and enable it via
13+
/sys/kernel/debug/tracing/events/uprobes/<EVENT>/enabled.
14+
15+
However unlike kprobe-event tracer, the uprobe event interface expects the
16+
user to calculate the offset of the probepoint in the object
17+
18+
Synopsis of uprobe_tracer
19+
-------------------------
20+
p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] : Set a probe
21+
22+
GRP : Group name. If omitted, use "uprobes" for it.
23+
EVENT : Event name. If omitted, the event name is generated
24+
based on SYMBOL+offs.
25+
PATH : path to an executable or a library.
26+
SYMBOL[+offs] : Symbol+offset where the probe is inserted.
27+
28+
FETCHARGS : Arguments. Each probe can have up to 128 args.
29+
%REG : Fetch register REG
30+
31+
Event Profiling
32+
---------------
33+
You can check the total number of probe hits and probe miss-hits via
34+
/sys/kernel/debug/tracing/uprobe_profile.
35+
The first column is event name, the second is the number of probe hits,
36+
the third is the number of probe miss-hits.
37+
38+
Usage examples
39+
--------------
40+
To add a probe as a new event, write a new definition to uprobe_events
41+
as below.
42+
43+
echo 'p: /bin/bash:0x4245c0' > /sys/kernel/debug/tracing/uprobe_events
44+
45+
This sets a uprobe at an offset of 0x4245c0 in the executable /bin/bash
46+
47+
echo > /sys/kernel/debug/tracing/uprobe_events
48+
49+
This clears all probe points.
50+
51+
The following example shows how to dump the instruction pointer and %ax
52+
a register at the probed text address. Here we are trying to probe
53+
function zfree in /bin/zsh
54+
55+
# cd /sys/kernel/debug/tracing/
56+
# cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp
57+
00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh
58+
# objdump -T /bin/zsh | grep -w zfree
59+
0000000000446420 g DF .text 0000000000000012 Base zfree
60+
61+
0x46420 is the offset of zfree in object /bin/zsh that is loaded at
62+
0x00400000. Hence the command to probe would be :
63+
64+
# echo 'p /bin/zsh:0x46420 %ip %ax' > uprobe_events
65+
66+
Please note: User has to explicitly calculate the offset of the probepoint
67+
in the object. We can see the events that are registered by looking at the
68+
uprobe_events file.
69+
70+
# cat uprobe_events
71+
p:uprobes/p_zsh_0x46420 /bin/zsh:0x0000000000046420
72+
73+
Right after definition, each event is disabled by default. For tracing these
74+
events, you need to enable it by:
75+
76+
# echo 1 > events/uprobes/enable
77+
78+
Lets disable the event after sleeping for some time.
79+
# sleep 20
80+
# echo 0 > events/uprobes/enable
81+
82+
And you can see the traced information via /sys/kernel/debug/tracing/trace.
83+
84+
# cat trace
85+
# tracer: nop
86+
#
87+
# TASK-PID CPU# TIMESTAMP FUNCTION
88+
# | | | | |
89+
zsh-24842 [006] 258544.995456: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
90+
zsh-24842 [007] 258545.000270: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
91+
zsh-24842 [002] 258545.043929: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
92+
zsh-24842 [004] 258547.046129: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
93+
94+
Each line shows us probes were triggered for a pid 24842 with ip being
95+
0x446421 and contents of ax register being 79.

arch/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ config OPTPROBES
7878

7979
config UPROBES
8080
bool "Transparent user-space probes (EXPERIMENTAL)"
81-
depends on ARCH_SUPPORTS_UPROBES && PERF_EVENTS
81+
depends on UPROBE_EVENTS && PERF_EVENTS
8282
default n
8383
help
8484
Uprobes is the user-space counterpart to kprobes: they

kernel/trace/Kconfig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,22 @@ config KPROBE_EVENT
386386
This option is also required by perf-probe subcommand of perf tools.
387387
If you want to use perf tools, this option is strongly recommended.
388388

389+
config UPROBE_EVENT
390+
bool "Enable uprobes-based dynamic events"
391+
depends on ARCH_SUPPORTS_UPROBES
392+
depends on MMU
393+
select UPROBES
394+
select PROBE_EVENTS
395+
select TRACING
396+
default n
397+
help
398+
This allows the user to add tracing events on top of userspace
399+
dynamic events (similar to tracepoints) on the fly via the trace
400+
events interface. Those events can be inserted wherever uprobes
401+
can probe, and record various registers.
402+
This option is required if you plan to use perf-probe subcommand
403+
of perf tools on user space applications.
404+
389405
config PROBE_EVENTS
390406
def_bool n
391407

kernel/trace/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,6 @@ ifeq ($(CONFIG_TRACING),y)
6262
obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
6363
endif
6464
obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o
65+
obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o
6566

6667
libftrace-y := ftrace.o

kernel/trace/trace.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ struct kretprobe_trace_entry_head {
103103
unsigned long ret_ip;
104104
};
105105

106+
struct uprobe_trace_entry_head {
107+
struct trace_entry ent;
108+
unsigned long ip;
109+
};
110+
106111
/*
107112
* trace_flag_type is an enumeration that holds different
108113
* states when a trace occurs. These are:

kernel/trace/trace_kprobe.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ static int create_trace_probe(int argc, char **argv)
525525

526526
/* Parse fetch argument */
527527
ret = traceprobe_parse_probe_arg(arg, &tp->size, &tp->args[i],
528-
is_return);
528+
is_return, true);
529529
if (ret) {
530530
pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
531531
goto error;

kernel/trace/trace_probe.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -550,14 +550,19 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
550550

551551
/* Recursive argument parser */
552552
static int parse_probe_arg(char *arg, const struct fetch_type *t,
553-
struct fetch_param *f, bool is_return)
553+
struct fetch_param *f, bool is_return, bool is_kprobe)
554554
{
555555
unsigned long param;
556556
long offset;
557557
char *tmp;
558558
int ret;
559559

560560
ret = 0;
561+
562+
/* Until uprobe_events supports only reg arguments */
563+
if (!is_kprobe && arg[0] != '%')
564+
return -EINVAL;
565+
561566
switch (arg[0]) {
562567
case '$':
563568
ret = parse_probe_vars(arg + 1, t, f, is_return);
@@ -619,7 +624,8 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
619624
return -ENOMEM;
620625

621626
dprm->offset = offset;
622-
ret = parse_probe_arg(arg, t2, &dprm->orig, is_return);
627+
ret = parse_probe_arg(arg, t2, &dprm->orig, is_return,
628+
is_kprobe);
623629
if (ret)
624630
kfree(dprm);
625631
else {
@@ -677,7 +683,7 @@ static int __parse_bitfield_probe_arg(const char *bf,
677683

678684
/* String length checking wrapper */
679685
int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
680-
struct probe_arg *parg, bool is_return)
686+
struct probe_arg *parg, bool is_return, bool is_kprobe)
681687
{
682688
const char *t;
683689
int ret;
@@ -703,7 +709,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
703709
}
704710
parg->offset = *size;
705711
*size += parg->type->size;
706-
ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return);
712+
ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return, is_kprobe);
707713

708714
if (ret >= 0 && t != NULL)
709715
ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);

kernel/trace/trace_probe.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
#define TP_FLAG_TRACE 1
6767
#define TP_FLAG_PROFILE 2
6868
#define TP_FLAG_REGISTERED 4
69+
#define TP_FLAG_UPROBE 8
6970

7071

7172
/* data_rloc: data relative location, compatible with u32 */
@@ -143,7 +144,7 @@ static inline int is_good_name(const char *name)
143144
}
144145

145146
extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
146-
struct probe_arg *parg, bool is_return);
147+
struct probe_arg *parg, bool is_return, bool is_kprobe);
147148

148149
extern int traceprobe_conflict_field_name(const char *name,
149150
struct probe_arg *args, int narg);

0 commit comments

Comments
 (0)