aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorSrikar Dronamraju <srikar@linux.vnet.ibm.com>2012-04-11 06:30:43 -0400
committerIngo Molnar <mingo@kernel.org>2012-05-07 08:30:17 -0400
commitf3f096cfedf8113380c56fc855275cc75cd8cf55 (patch)
treeb8d0553afc8cebf6dd320d094206e93df5d95794 /kernel/trace
parent8ab83f56475ec9151645a888dfe1941f4a92091d (diff)
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 <srikar@linux.vnet.ibm.com> Acked-by: Steven Rostedt <rostedt@goodmis.org> Acked-by: Masami 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.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/Kconfig16
-rw-r--r--kernel/trace/Makefile1
-rw-r--r--kernel/trace/trace.h5
-rw-r--r--kernel/trace/trace_kprobe.c2
-rw-r--r--kernel/trace/trace_probe.c14
-rw-r--r--kernel/trace/trace_probe.h3
-rw-r--r--kernel/trace/trace_uprobe.c788
7 files changed, 823 insertions, 6 deletions
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index ce5a5c54ac8f..ea4bff6295fc 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -386,6 +386,22 @@ config KPROBE_EVENT
386 This option is also required by perf-probe subcommand of perf tools. 386 This option is also required by perf-probe subcommand of perf tools.
387 If you want to use perf tools, this option is strongly recommended. 387 If you want to use perf tools, this option is strongly recommended.
388 388
389config 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
389config PROBE_EVENTS 405config PROBE_EVENTS
390 def_bool n 406 def_bool n
391 407
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index fa10d5ca5ab1..1734c03e048b 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -62,5 +62,6 @@ ifeq ($(CONFIG_TRACING),y)
62obj-$(CONFIG_KGDB_KDB) += trace_kdb.o 62obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
63endif 63endif
64obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o 64obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o
65obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o
65 66
66libftrace-y := ftrace.o 67libftrace-y := ftrace.o
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 95059f091a24..1bcdbec95a11 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -103,6 +103,11 @@ struct kretprobe_trace_entry_head {
103 unsigned long ret_ip; 103 unsigned long ret_ip;
104}; 104};
105 105
106struct uprobe_trace_entry_head {
107 struct trace_entry ent;
108 unsigned long ip;
109};
110
106/* 111/*
107 * trace_flag_type is an enumeration that holds different 112 * trace_flag_type is an enumeration that holds different
108 * states when a trace occurs. These are: 113 * states when a trace occurs. These are:
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index f8b777367d8e..b31d3d5699fe 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -525,7 +525,7 @@ static int create_trace_probe(int argc, char **argv)
525 525
526 /* Parse fetch argument */ 526 /* Parse fetch argument */
527 ret = traceprobe_parse_probe_arg(arg, &tp->size, &tp->args[i], 527 ret = traceprobe_parse_probe_arg(arg, &tp->size, &tp->args[i],
528 is_return); 528 is_return, true);
529 if (ret) { 529 if (ret) {
530 pr_info("Parse error at argument[%d]. (%d)\n", i, ret); 530 pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
531 goto error; 531 goto error;
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 8e526b9286e9..daa9980153af 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -550,7 +550,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,
550 550
551/* Recursive argument parser */ 551/* Recursive argument parser */
552static int parse_probe_arg(char *arg, const struct fetch_type *t, 552static 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)
554{ 554{
555 unsigned long param; 555 unsigned long param;
556 long offset; 556 long offset;
@@ -558,6 +558,11 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t,
558 int ret; 558 int ret;
559 559
560 ret = 0; 560 ret = 0;
561
562 /* Until uprobe_events supports only reg arguments */
563 if (!is_kprobe && arg[0] != '%')
564 return -EINVAL;
565
561 switch (arg[0]) { 566 switch (arg[0]) {
562 case '$': 567 case '$':
563 ret = parse_probe_vars(arg + 1, t, f, is_return); 568 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 return -ENOMEM; 624 return -ENOMEM;
620 625
621 dprm->offset = offset; 626 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);
623 if (ret) 629 if (ret)
624 kfree(dprm); 630 kfree(dprm);
625 else { 631 else {
@@ -677,7 +683,7 @@ static int __parse_bitfield_probe_arg(const char *bf,
677 683
678/* String length checking wrapper */ 684/* String length checking wrapper */
679int traceprobe_parse_probe_arg(char *arg, ssize_t *size, 685int 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)
681{ 687{
682 const char *t; 688 const char *t;
683 int ret; 689 int ret;
@@ -703,7 +709,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
703 } 709 }
704 parg->offset = *size; 710 parg->offset = *size;
705 *size += parg->type->size; 711 *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);
707 713
708 if (ret >= 0 && t != NULL) 714 if (ret >= 0 && t != NULL)
709 ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); 715 ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 2df9a18e0252..933708677814 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -66,6 +66,7 @@
66#define TP_FLAG_TRACE 1 66#define TP_FLAG_TRACE 1
67#define TP_FLAG_PROFILE 2 67#define TP_FLAG_PROFILE 2
68#define TP_FLAG_REGISTERED 4 68#define TP_FLAG_REGISTERED 4
69#define TP_FLAG_UPROBE 8
69 70
70 71
71/* data_rloc: data relative location, compatible with u32 */ 72/* data_rloc: data relative location, compatible with u32 */
@@ -143,7 +144,7 @@ static inline int is_good_name(const char *name)
143} 144}
144 145
145extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size, 146extern 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);
147 148
148extern int traceprobe_conflict_field_name(const char *name, 149extern int traceprobe_conflict_field_name(const char *name,
149 struct probe_arg *args, int narg); 150 struct probe_arg *args, int narg);
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
new file mode 100644
index 000000000000..2b36ac68549e
--- /dev/null
+++ b/kernel/trace/trace_uprobe.c
@@ -0,0 +1,788 @@
1/*
2 * uprobes-based tracing events
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Copyright (C) IBM Corporation, 2010-2012
18 * Author: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
19 */
20
21#include <linux/module.h>
22#include <linux/uaccess.h>
23#include <linux/uprobes.h>
24#include <linux/namei.h>
25
26#include "trace_probe.h"
27
28#define UPROBE_EVENT_SYSTEM "uprobes"
29
30/*
31 * uprobe event core functions
32 */
33struct trace_uprobe;
34struct uprobe_trace_consumer {