Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 306649
b: refs/heads/master
c: f3f096c
h: refs/heads/master
i:
  306647: 0d7f0a1
v: v3
  • Loading branch information
Srikar Dronamraju authored and Ingo Molnar committed May 7, 2012
1 parent f77055d commit ed27e40
Show file tree
Hide file tree
Showing 10 changed files with 920 additions and 8 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8ab83f56475ec9151645a888dfe1941f4a92091d
refs/heads/master: f3f096cfedf8113380c56fc855275cc75cd8cf55
95 changes: 95 additions & 0 deletions trunk/Documentation/trace/uprobetracer.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
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.
2 changes: 1 addition & 1 deletion trunk/arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ config OPTPROBES

config UPROBES
bool "Transparent user-space probes (EXPERIMENTAL)"
depends on ARCH_SUPPORTS_UPROBES && PERF_EVENTS
depends on UPROBE_EVENTS && PERF_EVENTS
default n
help
Uprobes is the user-space counterpart to kprobes: they
Expand Down
16 changes: 16 additions & 0 deletions trunk/kernel/trace/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,22 @@ config KPROBE_EVENT
This option is also required by perf-probe subcommand of perf tools.
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
def_bool n

Expand Down
1 change: 1 addition & 0 deletions trunk/kernel/trace/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,6 @@ ifeq ($(CONFIG_TRACING),y)
obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
endif
obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o
obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o

libftrace-y := ftrace.o
5 changes: 5 additions & 0 deletions trunk/kernel/trace/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ struct kretprobe_trace_entry_head {
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
* states when a trace occurs. These are:
Expand Down
2 changes: 1 addition & 1 deletion trunk/kernel/trace/trace_kprobe.c
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ static int create_trace_probe(int argc, char **argv)

/* Parse fetch argument */
ret = traceprobe_parse_probe_arg(arg, &tp->size, &tp->args[i],
is_return);
is_return, true);
if (ret) {
pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
goto error;
Expand Down
14 changes: 10 additions & 4 deletions trunk/kernel/trace/trace_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,14 +550,19 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,

/* Recursive argument parser */
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;
long offset;
char *tmp;
int ret;

ret = 0;

/* Until uprobe_events supports only reg arguments */
if (!is_kprobe && arg[0] != '%')
return -EINVAL;

switch (arg[0]) {
case '$':
ret = parse_probe_vars(arg + 1, t, f, is_return);
Expand Down Expand Up @@ -619,7 +624,8 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
return -ENOMEM;

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)
kfree(dprm);
else {
Expand Down Expand Up @@ -677,7 +683,7 @@ static int __parse_bitfield_probe_arg(const char *bf,

/* String length checking wrapper */
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;
int ret;
Expand All @@ -703,7 +709,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
}
parg->offset = *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)
ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
Expand Down
3 changes: 2 additions & 1 deletion trunk/kernel/trace/trace_probe.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
#define TP_FLAG_TRACE 1
#define TP_FLAG_PROFILE 2
#define TP_FLAG_REGISTERED 4
#define TP_FLAG_UPROBE 8


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

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,
struct probe_arg *args, int narg);
Expand Down
Loading

0 comments on commit ed27e40

Please sign in to comment.