lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 18 May 2010 22:30:54 +0530
From:	Srikar Dronamraju <srikar@...ux.vnet.ibm.com>
To:	Peter Zijlstra <peterz@...radead.org>, Ingo Molnar <mingo@...e.hu>
Cc:	Masami Hiramatsu <mhiramat@...hat.com>, Mel Gorman <mel@....ul.ie>,
	Srikar Dronamraju <srikar@...ux.vnet.ibm.com>,
	Steven Rostedt <rostedt@...dmis.org>,
	Randy Dunlap <rdunlap@...otime.net>,
	Linus Torvalds <torvalds@...ux-foundation.org>,
	Roland McGrath <roland@...hat.com>,
	"H. Peter Anvin" <hpa@...or.com>,
	Christoph Hellwig <hch@...radead.org>,
	Ananth N Mavinakayanahalli <ananth@...ibm.com>,
	Oleg Nesterov <oleg@...hat.com>,
	Mark Wielaard <mjw@...hat.com>,
	Mathieu Desnoyers <mathieu.desnoyers@...icios.com>,
	Andrew Morton <akpm@...ux-foundation.org>,
	Jim Keniston <jkenisto@...ux.vnet.ibm.com>,
	Frederic Weisbecker <fweisbec@...il.com>,
	"Rafael J. Wysocki" <rjw@...k.pl>,
	"Frank Ch. Eigler" <fche@...hat.com>,
	LKML <linux-kernel@...r.kernel.org>,
	"Paul E. McKenney" <paulmck@...ux.vnet.ibm.com>
Subject: [PATCH v4 13/13] perf: perf interface for uprobes.


This patch enhances perf probe to accept pid and user vaddr.
This patch provides very basic support for uprobes.

Changelog from v3: (addressed comments from Masami Hiramatsu)
	* Every process id has a different group name.
	* event name starts with function name.
	* If vaddr is specified, event name has vaddr appended
	  along with function name, (this is to avoid subsequent probes
	  using same event name.)
	* warning if -p and --list options are used together.

	Also dso can either be a short name or absolute path.

TODO:
Rebase to -tip tree. (targeted for v5)
Update perf-probes.txt.
Global tracing.

Here is a terminal snapshot of placing, using and removing a probe on a
process with pid 3329 (corresponding to zsh)

[ Probing a function in the executable using function name  ]
-------------------------------------------------------------
[root@...D]# perf probe -p 7057 zfree@zsh
Added new event:
  probe_7057:zfree                       (on 0x446420)

You can now use it on all perf tools, such as:

	perf record -e probe_7057:zfree -a sleep 1
[root@...D]# perf probe --list
probe_7057:zfree                       (on 7057:0x0000000000446420)
[root@...D]# cat /sys/kernel/debug/tracing/uprobe_events
p:probe_7057/zfree 7057:0x0000000000446420
[root@...D]# perf record -f -e probe_7057:zfree -a sleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.039 MB perf.data (~1716 samples) ]
[root@...D]# perf probe -p 7057 --del probe_7057:zfree
Remove event: probe_7057:zfree
[root@...D]# perf report
# Samples: 447
#
# Overhead          Command  Shared Object  Symbol
# ........  ...............  .............  ......
#
   100.00%              zsh  zsh            [.] zfree


#
# (For a higher level overview, try: perf report --sort comm,dso)
#

[ Probing a function + offset ]
-------------------------------
[root@...D]# perf probe -p 7057 zfree@...+5
Added new event:
  probe_7057:zfree                         (on 0x446425)

You can now use it on all perf tools, such as:

	perf record -e probe_7057:zfree -a sleep 1
[root@...D]# perf probe --list
probe_7057:zfree                       (on 7057:0x0000000000446425)
[root@...D]# cat /sys/kernel/debug/tracing/uprobe_events
p:probe_7057/zfree 7057:0x0000000000446425
[root@...D]# perf record -f -e probe_7057:zfree -a sleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.036 MB perf.data (~1590 samples) ]
[root@...D]# perf probe -p 7057 --del probe_7057:zfree
Remove event: probe_7057:zfree
[root@...D]# perf report
# Samples: 18
#
# Overhead          Command  Shared Object  Symbol
# ........  ...............  .............  ......
#
   100.00%              zsh  zsh            [.] zfree


#
# (For a higher level overview, try: perf report --sort comm,dso)
#


[ Probing a library function using function name ]
--------------------------------------------------
[root@...D]# perf probe -p 7057 write@...c-2.5.so
Added new event:
  probe_7057:write                       (on 0x36010c6060)

You can now use it on all perf tools, such as:

	perf record -e probe_7057:write -a sleep 1
[root@...D]# perf probe --list
probe_7057:write                       (on 7057:0x00000036010c6060)
[root@...D]# cat /sys/kernel/debug/tracing/uprobe_events
p:probe_7057/write 7057:0x00000036010c6060
[root@...D]# perf record -f -e probe_7057:write -a sleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.040 MB perf.data (~1738 samples) ]
[root@...D]# perf probe -p 7057 --del probe_7057:write
Remove event: probe_7057:write
[root@...D]# perf report
# Samples: 11
#
# Overhead          Command       Shared Object  Symbol
# ........  ...............  ..................  ......
#
   100.00%              zsh  libc-2.5.so         [.] __GI___libc_write


#
# (For a higher level overview, try: perf report --sort comm,dso)
#

[ Probing a library function using function name and absolute path ]
---------------------------------------------------------------------
[root@...D]# perf probe -p 7057 write@...b64/libc-2.5.so
Added new event:
  probe_7057:write                       (on 0x36010c6060)

You can now use it on all perf tools, such as:

	perf record -e probe_7057:write -a sleep 1
[root@...D]# perf probe --list
probe_7057:write                       (on 7057:0x00000036010c6060)
[root@...D]# cat /sys/kernel/debug/tracing/uprobe_events
p:probe_7057/write 7057:0x00000036010c6060
[root@...D]# perf record -f -e probe_7057:write -a sleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.040 MB perf.data (~1738 samples) ]
[root@...D]# perf probe -p 7057 --del probe_7057:write
Remove event: probe_7057:write
[root@...D]# perf report
# Samples: 11
#
# Overhead          Command       Shared Object  Symbol
# ........  ...............  ..................  ......
#
   100.00%              zsh  libc-2.5.so         [.] __GI___libc_write


#
# (For a higher level overview, try: perf report --sort comm,dso)
#

[ Probing using vaddr 0x0000000000446420 (corresponding to zfree)]
-------------------------------------------------------------------
[root@...D]# perf probe -p 7057 0x0000000000446420
Added new event:
  probe_7057:zfree_446420          (on 0x0000000000446420)

You can now use it on all perf tools, such as:

        perf record -e probe_7057:zfree_446420 -a sleep 1

[root@...D]# perf record -e probe_7057:zfree_446420 -a sleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.041 MB perf.data (~1797 samples) ]
[root@...D]# perf report
#
# Samples: 628
#
# Overhead          Command  Shared Object  Symbol
# ........  ...............  .............  ......
#
   100.00%              zsh  zsh            [.] zfree


#
# (For a higher level overview, try: perf report --sort comm,dso)
#
[root@...D]# perf report --sort comm,dso
# Samples: 628
#
# Overhead          Command  Shared Object
# ........  ...............  .............
#
   100.00%              zsh  zsh


[root@...D]# perf probe --list
  probe_7057:zfree_446420          (on 7057:0x0000000000446420)
[root@...D]#  perf list | grep probe
  probe_7057:zfree_446420            [Tracepoint event]
[root@...D]# perf probe -p 7057 --del probe_7057:zfree_446420
Remove event: probe_7057:zfree_446420
[root@...D]#


Another example for a shared library: write stub in libc. (corresponds to
0x00000036010c6060)

on a vaddr
[ Probing a libc vaddr 0x00000036010c6060 (corresponding to write) ]
[root@...D]# perf probe -p 7057 0x00000036010c6060
dded new event:
  probe_7057:__GI___libc_write_36010c6060          (on 0x00000036010c6060)

You can now use it on all perf tools, such as:

        perf record -e probe_7057:__GI___libc_write_36010c6060 -a sleep 1

[root@...D]# perf record -f -e probe_7057:__GI___libc_write_36010c6060 -a sleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.040 MB perf.data (~1748 samples) ]
[root@...D]# perf report
# Samples: 24
#
# Overhead          Command       Shared Object  Symbol
# ........  ...............  ..................  ......
#
   100.00%              zsh  libc-2.5.so         [.] __GI___libc_write


#
# (For a higher level overview, try: perf report --sort comm,dso)
#
[root@...D]#

[ Probing using a function without specifying a dso (corresponding to zfree)]
-------------------------------------------------------------------
[root@...D]# perf probe -p 7057 zfree
Added new event:
  probe_7057:zfree		          (on 0x0000000000446420)

You can now use it on all perf tools, such as:

        perf record -e probe_7057:zfree -a sleep 1

[root@...D]# perf record -e probe_7057:zfree -a sleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.041 MB perf.data (~1797 samples) ]
[root@...D]# perf report
#
# Samples: 628
#
# Overhead          Command  Shared Object  Symbol
# ........  ...............  .............  ......
#
   100.00%              zsh  zsh            [.] zfree


#
# (For a higher level overview, try: perf report --sort comm,dso)
#
[root@...D]#

Signed-off-by: Srikar Dronamraju <srikar@...ux.vnet.ibm.com>
---

 tools/perf/builtin-probe.c     |   38 +++++-
 tools/perf/builtin-top.c       |   20 ---
 tools/perf/util/event.c        |   20 +++
 tools/perf/util/event.h        |    1 
 tools/perf/util/probe-event.c  |  237 +++++++++++++++++++++++++++++++++-------
 tools/perf/util/probe-event.h  |    9 +-
 tools/perf/util/probe-finder.h |    1 
 7 files changed, 252 insertions(+), 74 deletions(-)


diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 152d6c9..ce59282 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -55,6 +55,7 @@ static struct {
 	bool force_add;
 	bool show_lines;
 	int nr_probe;
+	pid_t pid;
 	struct probe_point probes[MAX_PROBES];
 	struct strlist *dellist;
 	struct map_groups kmap_groups;
@@ -73,7 +74,7 @@ static void parse_probe_event(const char *str)
 		die("Too many probes (> %d) are specified.", MAX_PROBES);
 
 	/* Parse perf-probe event into probe_point */
-	parse_perf_probe_event(str, pp, &session.need_dwarf);
+	parse_perf_probe_event(str, pp, &session.need_dwarf, session.pid);
 
 	pr_debug("%d arguments\n", pp->nr_args);
 }
@@ -203,6 +204,8 @@ static const struct option options[] = {
 		     "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]",
 		     "Show source code lines.", opt_show_lines),
 #endif
+	OPT_INTEGER('p', "pid", &session.pid,
+	"specify a pid for a uprobes based probe"),
 	OPT_END()
 };
 
@@ -258,12 +261,16 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			pr_warning("  Error: Don't use --list with --line.\n");
 			usage_with_options(probe_usage, options);
 		}
+		if (session.pid) {
+			pr_warning("  Error: Don't use --list with -pid.\n");
+			usage_with_options(probe_usage, options);
+		}
 		show_perf_probe_events();
 		return 0;
 	}
 
 #ifndef NO_DWARF_SUPPORT
-	if (session.show_lines) {
+	if (session.show_lines && !session.pid) {
 		if (session.nr_probe != 0 || session.dellist) {
 			pr_warning("  Error: Don't use --line with"
 				   " --add/--del.\n");
@@ -283,12 +290,19 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 #endif
 
 	if (session.dellist) {
-		del_trace_kprobe_events(session.dellist);
+		if (session.pid)
+			del_trace_uprobe_events(session.dellist);
+		else
+			del_trace_kprobe_events(session.dellist);
+
 		strlist__delete(session.dellist);
 		if (session.nr_probe == 0)
 			return 0;
 	}
 
+	if (session.pid)
+		goto end_dwarf;
+
 	/* Add probes */
 	init_vmlinux();
 
@@ -334,18 +348,19 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		break;
 	}
 	close(fd);
-
-end_dwarf:
 #endif /* !NO_DWARF_SUPPORT */
 
+end_dwarf:
 	/* Synthesize probes without dwarf */
 	for (i = 0; i < session.nr_probe; i++) {
 		pp = &session.probes[i];
 		if (pp->found)	/* This probe is already found. */
 			continue;
 
-		evaluate_probe_point(pp);
-		ret = synthesize_trace_kprobe_event(pp);
+		if (!session.pid)
+			evaluate_probe_point(pp);
+
+		ret = synthesize_trace_probe_event(pp);
 		if (ret == -E2BIG)
 			die("probe point definition becomes too long.");
 		else if (ret < 0)
@@ -353,8 +368,11 @@ end_dwarf:
 	}
 
 	/* Settng up probe points */
-	add_trace_kprobe_events(session.probes, session.nr_probe,
-				session.force_add);
+	if (session.pid)
+		add_trace_uprobe_events(session.probes, session.nr_probe,
+					session.force_add, session.pid);
+	else
+		add_trace_kprobe_events(session.probes, session.nr_probe,
+					session.force_add);
 	return 0;
 }
-
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 1f52932..430d910 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1005,26 +1005,6 @@ static void event__process_sample(const event_t *self,
 	}
 }
 
-static int event__process(event_t *event, struct perf_session *session)
-{
-	switch (event->header.type) {
-	case PERF_RECORD_COMM:
-		event__process_comm(event, session);
-		break;
-	case PERF_RECORD_MMAP:
-		event__process_mmap(event, session);
-		break;
-	case PERF_RECORD_FORK:
-	case PERF_RECORD_EXIT:
-		event__process_task(event, session);
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
 struct mmap_data {
 	int			counter;
 	void			*base;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 705ec63..e5190f2 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -432,6 +432,26 @@ int event__process_task(event_t *self, struct perf_session *session)
 	return 0;
 }
 
+int event__process(event_t *event, struct perf_session *session)
+{
+	switch (event->header.type) {
+	case PERF_RECORD_COMM:
+		event__process_comm(event, session);
+		break;
+	case PERF_RECORD_MMAP:
+		event__process_mmap(event, session);
+		break;
+	case PERF_RECORD_FORK:
+	case PERF_RECORD_EXIT:
+		event__process_task(event, session);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 void thread__find_addr_map(struct thread *self,
 			   struct perf_session *session, u8 cpumode,
 			   enum map_type type, u64 addr,
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index a33b949..282486b 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -128,6 +128,7 @@ int event__process_comm(event_t *self, struct perf_session *session);
 int event__process_lost(event_t *self, struct perf_session *session);
 int event__process_mmap(event_t *self, struct perf_session *session);
 int event__process_task(event_t *self, struct perf_session *session);
+int event__process(event_t *event, struct perf_session *session);
 
 struct addr_location;
 int event__preprocess_sample(const event_t *self, struct perf_session *session,
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 7c004b6..afa52a0 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -41,6 +41,7 @@
 #include "color.h"
 #include "parse-events.h"  /* For debugfs_path */
 #include "probe-event.h"
+#include "session.h"
 
 #define MAX_CMDLEN 256
 #define MAX_PROBE_ARGS 128
@@ -112,6 +113,79 @@ static bool check_event_name(const char *name)
 	return true;
 }
 
+/*
+ * uprobe_events only accepts address:
+ * Convert function and any offset to address
+ */
+static void convert_name_to_addr(struct probe_point *pp)
+{
+	struct perf_session *session;
+	struct thread *thread;
+	struct symbol *sym;
+	struct map *map;
+	char *name;
+	unsigned long long vaddr;
+
+	/* check if user has specifed a virtual address */
+	vaddr = strtoul(pp->function, NULL, 0);
+	session = perf_session__new(NULL, O_WRONLY, false);
+	DIE_IF(session == NULL);
+	symbol_conf.try_vmlinux_path = false;
+	if (!vaddr)
+		symbol_conf.sort_by_name = true;
+	if (symbol__init() < 0)
+		semantic_error("Cannot initialize symbols.");
+
+	event__synthesize_thread(pp->upid, event__process, session);
+
+	thread = perf_session__findnew(session, pp->upid);
+	DIE_IF(thread == NULL);
+
+	if (vaddr) {
+		if (pp->event)
+			return;
+
+		pp->event = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
+		sym = map_groups__find_function(&thread->mg, vaddr, NULL);
+		if (!sym)
+			snprintf(pp->event, MAX_PROBE_ARGS, "p_%llx", vaddr);
+		else
+			snprintf(pp->event, MAX_PROBE_ARGS, "%s_%llx",
+							sym->name, vaddr);
+		return;
+	}
+
+	if (!pp->file)
+		/* Lets find the function in the executable. */
+		name = strdup(thread->comm);
+	else
+		name = basename(make_absolute_path(pp->file));
+
+	DIE_IF(name == NULL);
+
+	map = map_groups__find_by_name(&thread->mg, MAP__FUNCTION, name);
+	if (!map)
+		semantic_error("Cannot find appropriate DSO.");
+
+	sym = map__find_symbol_by_name(map, pp->function, NULL);
+	if (!sym)
+		semantic_error("Cannot find appropriate Symbol.");
+
+	if (map->start > sym->start)
+		vaddr = map->start;
+	vaddr += sym->start + pp->offset + map->pgoff;
+	pp->offset = 0;
+
+	if (!pp->event)
+		pp->event = pp->function;
+	else
+		free(pp->function);
+	pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
+	if (!pp->function)
+		die("Failed to allocate memory by zalloc.");
+	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
+}
+
 /* Parse probepoint definition. */
 static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 {
@@ -166,7 +240,8 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 			*ptr++ = '\0';
 		}
 		switch (c) {
-		case ':':	/* Line number */
+		case ':':
+			/* Line number */
 			pp->line = strtoul(arg, &tmp, 0);
 			if (*tmp != '\0')
 				semantic_error("There is non-digit char"
@@ -216,6 +291,9 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 	if (pp->retprobe && !pp->function)
 		semantic_error("Return probe requires an entry function.");
 
+	if (pp->upid && !pp->function)
+		semantic_error("No function specified for uprobes");
+
 	if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe)
 		semantic_error("Offset/Line/Lazy pattern can't be used with "
 			       "return probe.");
@@ -223,11 +301,14 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 	pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n",
 		 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
 		 pp->lazy_line);
+
+	if (pp->upid)
+		convert_name_to_addr(pp);
 }
 
 /* Parse perf-probe event definition */
 void parse_perf_probe_event(const char *str, struct probe_point *pp,
-			    bool *need_dwarf)
+			    bool *need_dwarf, pid_t pid)
 {
 	char **argv;
 	int argc, i;
@@ -241,6 +322,7 @@ void parse_perf_probe_event(const char *str, struct probe_point *pp,
 		semantic_error("Too many arguments");
 
 	/* Parse probe point */
+	pp->upid = pid;
 	parse_perf_probe_probepoint(argv[0], pp);
 	if (pp->file || pp->line || pp->lazy_line)
 		*need_dwarf = true;
@@ -263,15 +345,15 @@ void parse_perf_probe_event(const char *str, struct probe_point *pp,
 	argv_free(argv);
 }
 
-/* Parse kprobe_events event into struct probe_point */
-void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
+/* Parse kprobe_events (uprobe_events) event into struct probe_point */
+void parse_trace_probe_event(const char *str, struct probe_point *pp)
 {
 	char pr;
 	char *p;
 	int ret, i, argc;
 	char **argv;
 
-	pr_debug("Parsing kprobe_events: %s\n", str);
+	pr_debug("Parsing probe_events: %s\n", str);
 	argv = argv_split(str, &argc);
 	if (!argv)
 		die("argv_split failed.");
@@ -375,7 +457,7 @@ error:
 	return ret;
 }
 
-int synthesize_trace_kprobe_event(struct probe_point *pp)
+int synthesize_trace_probe_event(struct probe_point *pp)
 {
 	char *buf;
 	int i, len, ret;
@@ -383,7 +465,11 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
 	pp->probes[0] = buf = zalloc(MAX_CMDLEN);
 	if (!buf)
 		die("Failed to allocate memory by zalloc.");
-	ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
+	if (pp->offset)
+		ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function,
+					pp->offset);
+	else
+		ret = e_snprintf(buf, MAX_CMDLEN, "%s", pp->function);
 	if (ret <= 0)
 		goto error;
 	len = ret;
@@ -426,8 +512,8 @@ static int open_kprobe_events(int flags, int mode)
 	return ret;
 }
 
-/* Get raw string list of current kprobe_events */
-static struct strlist *get_trace_kprobe_event_rawlist(int fd)
+/* Get raw string list of current kprobe_events  or uprobe_events */
+static struct strlist *get_trace_probe_event_rawlist(int fd)
 {
 	int ret, idx;
 	FILE *fp;
@@ -455,6 +541,27 @@ static struct strlist *get_trace_kprobe_event_rawlist(int fd)
 	return sl;
 }
 
+static int open_uprobe_events(int flags, int mode)
+{
+	char buf[PATH_MAX];
+	int ret;
+
+	ret = e_snprintf(buf, PATH_MAX, "%s/../uprobe_events", debugfs_path);
+	if (ret < 0)
+		die("Failed to make uprobe_events path.");
+
+	ret = open(buf, flags, mode);
+	if (ret < 0) {
+		if (errno == ENOENT)
+			die("uprobe_events file does not exist -"
+			    " please rebuild with CONFIG_UPROBE_EVENT.");
+		else
+			die("Could not open uprobe_events file: %s",
+			    strerror(errno));
+	}
+	return ret;
+}
+
 /* Free and zero clear probe_point */
 static void clear_probe_point(struct probe_point *pp)
 {
@@ -500,9 +607,8 @@ static void show_perf_probe_event(const char *event, const char *place,
 }
 
 /* List up current perf-probe events */
-void show_perf_probe_events(void)
+static void __show_perf_probe_events(int fd)
 {
-	int fd;
 	struct probe_point pp;
 	struct strlist *rawlist;
 	struct str_node *ent;
@@ -510,22 +616,31 @@ void show_perf_probe_events(void)
 	setup_pager();
 	memset(&pp, 0, sizeof(pp));
 
-	fd = open_kprobe_events(O_RDONLY, 0);
-	rawlist = get_trace_kprobe_event_rawlist(fd);
-	close(fd);
-
+	rawlist = get_trace_probe_event_rawlist(fd);
 	strlist__for_each(ent, rawlist) {
-		parse_trace_kprobe_event(ent->s, &pp);
+		parse_trace_probe_event(ent->s, &pp);
 		/* Synthesize only event probe point */
 		synthesize_perf_probe_point(&pp);
 		/* Show an event */
 		show_perf_probe_event(pp.event, pp.probes[0], &pp);
 		clear_probe_point(&pp);
 	}
-
 	strlist__delete(rawlist);
 }
 
+void show_perf_probe_events(void)
+{
+	int fd;
+
+	fd = open_kprobe_events(O_RDONLY, 0);
+	__show_perf_probe_events(fd);
+	close(fd);
+
+	fd = open_uprobe_events(O_RDONLY, 0);
+	__show_perf_probe_events(fd);
+	close(fd);
+}
+
 /* Get current perf-probe event names */
 static struct strlist *get_perf_event_names(int fd, bool include_group)
 {
@@ -535,11 +650,11 @@ static struct strlist *get_perf_event_names(int fd, bool include_group)
 	struct probe_point pp;
 
 	memset(&pp, 0, sizeof(pp));
-	rawlist = get_trace_kprobe_event_rawlist(fd);
+	rawlist = get_trace_probe_event_rawlist(fd);
 
 	sl = strlist__new(true, NULL);
 	strlist__for_each(ent, rawlist) {
-		parse_trace_kprobe_event(ent->s, &pp);
+		parse_trace_probe_event(ent->s, &pp);
 		if (include_group) {
 			if (e_snprintf(buf, 128, "%s:%s", pp.group,
 				       pp.event) < 0)
@@ -555,7 +670,7 @@ static struct strlist *get_perf_event_names(int fd, bool include_group)
 	return sl;
 }
 
-static void write_trace_kprobe_event(int fd, const char *buf)
+static void write_trace_probe_event(int fd, const char *buf)
 {
 	int ret;
 
@@ -566,11 +681,10 @@ static void write_trace_kprobe_event(int fd, const char *buf)
 }
 
 static void get_new_event_name(char *buf, size_t len, const char *base,
-			       struct strlist *namelist, bool allow_suffix)
+	       struct strlist *namelist, bool allow_suffix)
 {
 	int i, ret;
 
-	/* Try no suffix */
 	ret = e_snprintf(buf, len, "%s", base);
 	if (ret < 0)
 		die("snprintf() failed: %s", strerror(-ret));
@@ -595,38 +709,54 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
 		die("Too many events are on the same function.");
 }
 
-void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
-			     bool force_add)
+static void add_trace_probe_events(int fd, struct probe_point *probes,
+		int nr_probes, bool force_add, pid_t pid)
 {
-	int i, j, fd;
+	int i, j;
 	struct probe_point *pp;
 	char buf[MAX_CMDLEN];
+	char tempbuf[MAX_CMDLEN];
 	char event[64];
 	struct strlist *namelist;
 	bool allow_suffix;
 
-	fd = open_kprobe_events(O_RDWR, O_APPEND);
 	/* Get current event names */
 	namelist = get_perf_event_names(fd, false);
 
 	for (j = 0; j < nr_probes; j++) {
 		pp = probes + j;
+		pp->upid = pid;
+		if (pid)
+			snprintf(tempbuf, MAX_CMDLEN, "%d:", pid);
 		if (!pp->event)
 			pp->event = strdup(pp->function);
-		if (!pp->group)
-			pp->group = strdup(PERFPROBE_GROUP);
+		if (!pp->group) {
+			if (!pid)
+				pp->group = strdup(PERFPROBE_GROUP);
+			else {
+				/*
+				 * For uprobes based probes create a group
+				 * probe_<pid>.
+				 */
+				pp->group = zalloc(sizeof(char *)
+							* MAX_PROBE_ARGS);
+				snprintf(pp->group, MAX_PROBE_ARGS, "%s_%d",
+						PERFPROBE_GROUP, pid);
+			}
+		}
 		DIE_IF(!pp->event || !pp->group);
 		/* If force_add is true, suffix search is allowed */
 		allow_suffix = force_add;
 		for (i = 0; i < pp->found; i++) {
 			/* Get an unused new event name */
 			get_new_event_name(event, 64, pp->event, namelist,
-					   allow_suffix);
-			snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
+							   allow_suffix);
+			snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s\n",
 				 pp->retprobe ? 'r' : 'p',
 				 pp->group, event,
+				 pp->upid ? tempbuf : " ",
 				 pp->probes[i]);
-			write_trace_kprobe_event(fd, buf);
+			write_trace_probe_event(fd, buf);
 			printf("Added new event:\n");
 			/* Get the first parameter (probe-point) */
 			sscanf(pp->probes[i], "%s", buf);
@@ -647,10 +777,25 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
 	printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
 
 	strlist__delete(namelist);
+}
+
+void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
+			     bool force_add)
+{
+	int fd = open_kprobe_events(O_RDWR, O_APPEND);
+	add_trace_probe_events(fd, probes, nr_probes, force_add, 0);
+	close(fd);
+}
+
+void add_trace_uprobe_events(struct probe_point *probes, int nr_probes,
+			     bool force_add, pid_t pid)
+{
+	int fd = open_uprobe_events(O_RDWR, O_APPEND);
+	add_trace_probe_events(fd, probes, nr_probes, force_add, pid);
 	close(fd);
 }
 
-static void __del_trace_kprobe_event(int fd, struct str_node *ent)
+static void __del_trace_probe_event(int fd, struct str_node *ent)
 {
 	char *p;
 	char buf[128];
@@ -663,11 +808,11 @@ static void __del_trace_kprobe_event(int fd, struct str_node *ent)
 		die("Internal error: %s should have ':' but not.", ent->s);
 	*p = '/';
 
-	write_trace_kprobe_event(fd, buf);
+	write_trace_probe_event(fd, buf);
 	printf("Remove event: %s\n", ent->s);
 }
 
-static void del_trace_kprobe_event(int fd, const char *group,
+static void del_trace_probe_event(int fd, const char *group,
 				   const char *event, struct strlist *namelist)
 {
 	char buf[128];
@@ -681,14 +826,14 @@ static void del_trace_kprobe_event(int fd, const char *group,
 		strlist__for_each_safe(ent, n, namelist)
 			if (strglobmatch(ent->s, buf)) {
 				found++;
-				__del_trace_kprobe_event(fd, ent);
+				__del_trace_probe_event(fd, ent);
 				strlist__remove(namelist, ent);
 			}
 	} else {
 		ent = strlist__find(namelist, buf);
 		if (ent) {
 			found++;
-			__del_trace_kprobe_event(fd, ent);
+			__del_trace_probe_event(fd, ent);
 			strlist__remove(namelist, ent);
 		}
 	}
@@ -696,16 +841,13 @@ static void del_trace_kprobe_event(int fd, const char *group,
 		pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
 }
 
-void del_trace_kprobe_events(struct strlist *dellist)
+static void del_trace_probe_events(int fd, struct strlist *dellist)
 {
-	int fd;
 	const char *group, *event;
 	char *p, *str;
 	struct str_node *ent;
 	struct strlist *namelist;
 
-	fd = open_kprobe_events(O_RDWR, O_APPEND);
-	/* Get current event names */
 	namelist = get_perf_event_names(fd, true);
 
 	strlist__for_each(ent, dellist) {
@@ -723,10 +865,23 @@ void del_trace_kprobe_events(struct strlist *dellist)
 			event = str;
 		}
 		pr_debug("Group: %s, Event: %s\n", group, event);
-		del_trace_kprobe_event(fd, group, event, namelist);
+		del_trace_probe_event(fd, group, event, namelist);
 		free(str);
 	}
 	strlist__delete(namelist);
+}
+
+void del_trace_kprobe_events(struct strlist *dellist)
+{
+	int fd = open_kprobe_events(O_RDWR, O_APPEND);
+	del_trace_probe_events(fd, dellist);
+	close(fd);
+}
+
+void del_trace_uprobe_events(struct strlist *dellist)
+{
+	int fd = open_uprobe_events(O_RDWR, O_APPEND);
+	del_trace_probe_events(fd, dellist);
 	close(fd);
 }
 
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 711287d..bcb7ab2 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -7,14 +7,17 @@
 
 extern void parse_line_range_desc(const char *arg, struct line_range *lr);
 extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
-				   bool *need_dwarf);
+				   bool *need_dwarf, pid_t pid);
 extern int synthesize_perf_probe_point(struct probe_point *pp);
 extern int synthesize_perf_probe_event(struct probe_point *pp);
-extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
-extern int synthesize_trace_kprobe_event(struct probe_point *pp);
+extern int synthesize_trace_probe_event(struct probe_point *pp);
+extern void parse_trace_probe_event(const char *str, struct probe_point *pp);
 extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
 				    bool force_add);
 extern void del_trace_kprobe_events(struct strlist *dellist);
+extern void add_trace_uprobe_events(struct probe_point *probes, int nr_probes,
+				    bool force_add, pid_t pid);
+extern void del_trace_uprobe_events(struct strlist *dellist);
 extern void show_perf_probe_events(void);
 extern void show_line_range(struct line_range *lr);
 
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 21f7354..b4d8ebc 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -33,6 +33,7 @@ struct probe_point {
 
 	/* Output */
 	int			found;			/* Number of found probe points */
+	pid_t			upid;			/* uprobes only */
 	char			*probes[MAX_PROBES];	/* Output buffers (will be allocated)*/
 };
 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists