Commit f3f096cf authored by Srikar Dronamraju's avatar Srikar Dronamraju Committed by Ingo Molnar

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: default avatarSrikar Dronamraju <srikar@linux.vnet.ibm.com>
Acked-by: default avatarSteven Rostedt <rostedt@goodmis.org>
Acked-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com>
Cc: Linux-mm <linux-mm@kvack.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
Cc: Anton Arapov <anton@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20120411103043.GB29437@linux.vnet.ibm.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 8ab83f56
Uprobe-tracer: Uprobe-based Event Tracing
=========================================
Documentation written by Srikar Dronamraju
Overview
--------
Uprobe based trace events are similar to kprobe based trace events.
To enable this feature, build your kernel with CONFIG_UPROBE_EVENTS=y.
Similar to the kprobe-event tracer, this doesn't need to be activated via
current_tracer. Instead of that, add probe points via
/sys/kernel/debug/tracing/uprobe_events, and enable it via
/sys/kernel/debug/tracing/events/uprobes/<EVENT>/enabled.
However unlike kprobe-event tracer, the uprobe event interface expects the
user to calculate the offset of the probepoint in the object
Synopsis of uprobe_tracer
-------------------------
p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] : Set a probe
GRP : Group name. If omitted, use "uprobes" for it.
EVENT : Event name. If omitted, the event name is generated
based on SYMBOL+offs.
PATH : path to an executable or a library.
SYMBOL[+offs] : Symbol+offset where the probe is inserted.
FETCHARGS : Arguments. Each probe can have up to 128 args.
%REG : Fetch register REG
Event Profiling
---------------
You can check the total number of probe hits and probe miss-hits via
/sys/kernel/debug/tracing/uprobe_profile.
The first column is event name, the second is the number of probe hits,
the third is the number of probe miss-hits.
Usage examples
--------------
To add a probe as a new event, write a new definition to uprobe_events
as below.
echo 'p: /bin/bash:0x4245c0' > /sys/kernel/debug/tracing/uprobe_events
This sets a uprobe at an offset of 0x4245c0 in the executable /bin/bash
echo > /sys/kernel/debug/tracing/uprobe_events
This clears all probe points.
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
function 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
0x46420 is the offset of zfree in object /bin/zsh that is loaded at
0x00400000. Hence the command to probe would be :
# echo 'p /bin/zsh:0x46420 %ip %ax' > uprobe_events
Please note: User has to explicitly calculate the offset of the probepoint
in the object. We can see the events that are registered by looking at the
uprobe_events file.
# cat uprobe_events
p:uprobes/p_zsh_0x46420 /bin/zsh:0x0000000000046420
Right after definition, each event is disabled by default. For tracing these
events, you need to enable it by:
# echo 1 > events/uprobes/enable
Lets disable the event after sleeping for some time.
# sleep 20
# echo 0 > events/uprobes/enable
And you can see the traced information via /sys/kernel/debug/tracing/trace.
# 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
Each line shows us probes were triggered for a pid 24842 with ip being
0x446421 and contents of ax register being 79.
...@@ -78,7 +78,7 @@ config OPTPROBES ...@@ -78,7 +78,7 @@ config OPTPROBES
config UPROBES config UPROBES
bool "Transparent user-space probes (EXPERIMENTAL)" bool "Transparent user-space probes (EXPERIMENTAL)"
depends on ARCH_SUPPORTS_UPROBES && PERF_EVENTS depends on UPROBE_EVENTS && PERF_EVENTS
default n default n
help help
Uprobes is the user-space counterpart to kprobes: they Uprobes is the user-space counterpart to kprobes: they
......
...@@ -386,6 +386,22 @@ config KPROBE_EVENT ...@@ -386,6 +386,22 @@ config KPROBE_EVENT
This option is also required by perf-probe subcommand of perf tools. This option is also required by perf-probe subcommand of perf tools.
If you want to use perf tools, this option is strongly recommended. If you want to use perf tools, this option is strongly recommended.
config UPROBE_EVENT
bool "Enable uprobes-based dynamic events"
depends on ARCH_SUPPORTS_UPROBES
depends on MMU
select UPROBES
select PROBE_EVENTS
select TRACING
default n
help
This allows the user to add tracing events on top of userspace
dynamic events (similar to tracepoints) on the fly via the trace
events interface. Those events can be inserted wherever uprobes
can probe, and record various registers.
This option is required if you plan to use perf-probe subcommand
of perf tools on user space applications.
config PROBE_EVENTS config PROBE_EVENTS
def_bool n def_bool n
......
...@@ -62,5 +62,6 @@ ifeq ($(CONFIG_TRACING),y) ...@@ -62,5 +62,6 @@ ifeq ($(CONFIG_TRACING),y)
obj-$(CONFIG_KGDB_KDB) += trace_kdb.o obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
endif endif
obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o
obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o
libftrace-y := ftrace.o libftrace-y := ftrace.o
...@@ -103,6 +103,11 @@ struct kretprobe_trace_entry_head { ...@@ -103,6 +103,11 @@ struct kretprobe_trace_entry_head {
unsigned long ret_ip; unsigned long ret_ip;
}; };
struct uprobe_trace_entry_head {
struct trace_entry ent;
unsigned long ip;
};
/* /*
* trace_flag_type is an enumeration that holds different * trace_flag_type is an enumeration that holds different
* states when a trace occurs. These are: * states when a trace occurs. These are:
......
...@@ -525,7 +525,7 @@ static int create_trace_probe(int argc, char **argv) ...@@ -525,7 +525,7 @@ static int create_trace_probe(int argc, char **argv)
/* Parse fetch argument */ /* Parse fetch argument */
ret = traceprobe_parse_probe_arg(arg, &tp->size, &tp->args[i], ret = traceprobe_parse_probe_arg(arg, &tp->size, &tp->args[i],
is_return); is_return, true);
if (ret) { if (ret) {
pr_info("Parse error at argument[%d]. (%d)\n", i, ret); pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
goto error; goto error;
......
...@@ -550,7 +550,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, ...@@ -550,7 +550,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
/* Recursive argument parser */ /* Recursive argument parser */
static int parse_probe_arg(char *arg, const struct fetch_type *t, static int parse_probe_arg(char *arg, const struct fetch_type *t,
struct fetch_param *f, bool is_return) struct fetch_param *f, bool is_return, bool is_kprobe)
{ {
unsigned long param; unsigned long param;
long offset; long offset;
...@@ -558,6 +558,11 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, ...@@ -558,6 +558,11 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
int ret; int ret;
ret = 0; ret = 0;
/* Until uprobe_events supports only reg arguments */
if (!is_kprobe && arg[0] != '%')
return -EINVAL;
switch (arg[0]) { switch (arg[0]) {
case '$': case '$':
ret = parse_probe_vars(arg + 1, t, f, is_return); 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, ...@@ -619,7 +624,8 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
return -ENOMEM; return -ENOMEM;
dprm->offset = offset; dprm->offset = offset;
ret = parse_probe_arg(arg, t2, &dprm->orig, is_return); ret = parse_probe_arg(arg, t2, &dprm->orig, is_return,
is_kprobe);
if (ret) if (ret)
kfree(dprm); kfree(dprm);
else { else {
...@@ -677,7 +683,7 @@ static int __parse_bitfield_probe_arg(const char *bf, ...@@ -677,7 +683,7 @@ static int __parse_bitfield_probe_arg(const char *bf,
/* String length checking wrapper */ /* String length checking wrapper */
int traceprobe_parse_probe_arg(char *arg, ssize_t *size, int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
struct probe_arg *parg, bool is_return) struct probe_arg *parg, bool is_return, bool is_kprobe)
{ {
const char *t; const char *t;
int ret; int ret;
...@@ -703,7 +709,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, ...@@ -703,7 +709,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
} }
parg->offset = *size; parg->offset = *size;
*size += parg->type->size; *size += parg->type->size;
ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return); ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return, is_kprobe);
if (ret >= 0 && t != NULL) if (ret >= 0 && t != NULL)
ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
......
...@@ -66,6 +66,7 @@ ...@@ -66,6 +66,7 @@
#define TP_FLAG_TRACE 1 #define TP_FLAG_TRACE 1
#define TP_FLAG_PROFILE 2 #define TP_FLAG_PROFILE 2
#define TP_FLAG_REGISTERED 4 #define TP_FLAG_REGISTERED 4
#define TP_FLAG_UPROBE 8
/* data_rloc: data relative location, compatible with u32 */ /* data_rloc: data relative location, compatible with u32 */
...@@ -143,7 +144,7 @@ static inline int is_good_name(const char *name) ...@@ -143,7 +144,7 @@ static inline int is_good_name(const char *name)
} }
extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size, extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
struct probe_arg *parg, bool is_return); struct probe_arg *parg, bool is_return, bool is_kprobe);
extern int traceprobe_conflict_field_name(const char *name, extern int traceprobe_conflict_field_name(const char *name,
struct probe_arg *args, int narg); struct probe_arg *args, int narg);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment