All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-11 13:57 ` Srikar Dronamraju
  0 siblings, 0 replies; 24+ messages in thread
From: Srikar Dronamraju @ 2012-04-11 13:57 UTC (permalink / raw)
  To: Peter Zijlstra, Ingo Molnar
  Cc: Andrew Morton, Linus Torvalds, Ananth N Mavinakayanahalli,
	Jim Keniston, LKML, Linux-mm, Oleg Nesterov, Andi Kleen,
	Christoph Hellwig, Steven Rostedt, Arnaldo Carvalho de Melo,
	Masami Hiramatsu, Thomas Gleixner, Anton Arapov

From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>

- Enhances perf to probe user space executables and libraries.
- Enhances -F/--funcs option of "perf probe" to list possible probe points in
  an executable file or library.
- Documents userspace probing support in perf.

[ Probing a function in the executable using function name  ]
perf probe -x /bin/zsh zfree

[ Probing a library function using function name ]
perf probe -x /lib64/libc.so.6 malloc

[ list probe-able functions in an executable ]
perf probe -F -x /bin/zsh

[ list probe-able functions in an library]
perf probe -F -x /lib/libc.so.6

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

Changelog:
(v9)
- Handled comments from Masami Hiramatsu that helps reduce code changes.
- Handled usability comment(print complete name of file) from Ingo Molnar.

(v5)
- Removed the separate documentation change patch and added the
  documentation changes as part of this patch.

Usage:
[root@localhost ~]# perf probe -x /bin/zsh zfree
Add new event:
  probe_zsh:zfree      (on /bin/zsh:0x45400)

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

	perf record -e probe_zsh:zfree -aR sleep 1

[root@localhost ~]# perf record -e probe_zsh:zfree -aR sleep 15
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.314 MB perf.data (~13715 samples) ]
[root@localhost ~]# perf report --stdio
# Events: 3K probe_zsh:zfree
#
# Overhead  Command  Shared Object  Symbol
# ........  .......  .............  ......
#
   100.00%              zsh  zsh            [.] zfree


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

[ Probing a library function using function name ]
--------------------------------------------------
[root@localhost]#
[root@localhost]# perf probe -x /lib64/libc.so.6 malloc
Add new event:
  probe_libc:malloc    (on /lib64/libc-2.5.so:0x74dc0)

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

	perf record -e probe_libc:malloc -aR sleep 1

[root@localhost]#
[root@localhost]# perf probe --list
  probe_libc:malloc    (on /lib64/libc-2.5.so:0x0000000000074dc0)


Show last 10 functions in /bin/zsh.

# perf probe -F -x /bin/zsh | tail
zstrtol
ztrcmp
ztrdup
ztrduppfx
ztrftime
ztrlen
ztrncpy
ztrsub
zwarn
zwarnnam

Show first 10 functions in /lib/libc.so.6

# perf probe -F -x /lib/libc.so.6 | head
_IO_adjust_column
_IO_adjust_wcolumn
_IO_default_doallocate
_IO_default_finish
_IO_default_pbackfail
_IO_default_uflow
_IO_default_xsgetn
_IO_default_xsputn
_IO_do_write@@GLIBC_2.2.5
_IO_doallocbuf

 tools/perf/Documentation/perf-probe.txt |   15 +
 tools/perf/builtin-probe.c              |   42 +++
 tools/perf/util/probe-event.c           |  424 +++++++++++++++++++++++++------
 tools/perf/util/probe-event.h           |   12 +
 tools/perf/util/symbol.c                |    8 +
 tools/perf/util/symbol.h                |    1 
 6 files changed, 405 insertions(+), 97 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 2780d9c..fb673be 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -77,7 +77,8 @@ OPTIONS
 
 -F::
 --funcs::
-	Show available functions in given module or kernel.
+	Show available functions in given module or kernel. With -x/--exec,
+	can also list functions in a user space executable / shared library.
 
 --filter=FILTER::
 	(Only for --vars and --funcs) Set filter. FILTER is a combination of glob
@@ -98,6 +99,11 @@ OPTIONS
 --max-probes::
 	Set the maximum number of probe points for an event. Default is 128.
 
+-x::
+--exec=PATH::
+	Specify path to the executable or shared library file for user
+	space tracing. Can also be used with --funcs option.
+
 PROBE SYNTAX
 ------------
 Probe points are defined by following syntax.
@@ -182,6 +188,13 @@ Delete all probes on schedule().
 
  ./perf probe --del='schedule*'
 
+Add probes at zfree() function on /bin/zsh
+
+ ./perf probe -x /bin/zsh zfree
+
+Add probes at malloc() function on libc
+
+ ./perf probe -x /lib/libc.so.6 malloc
 
 SEE ALSO
 --------
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 4935c09..c1bf0d8 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -54,6 +54,7 @@ static struct {
 	bool show_ext_vars;
 	bool show_funcs;
 	bool mod_events;
+	bool uprobes;
 	int nevents;
 	struct perf_probe_event events[MAX_PROBES];
 	struct strlist *dellist;
@@ -75,6 +76,7 @@ static int parse_probe_event(const char *str)
 		return -1;
 	}
 
+	pev->uprobes = params.uprobes;
 	/* Parse a perf-probe command into event */
 	ret = parse_perf_probe_command(str, pev);
 	pr_debug("%d arguments\n", pev->nargs);
@@ -125,6 +127,28 @@ static int opt_del_probe_event(const struct option *opt __used,
 	return 0;
 }
 
+static int opt_set_target(const struct option *opt, const char *str,
+			int unset __used)
+{
+	int ret = -ENOENT;
+
+	if  (str && !params.target) {
+		if (!strcmp(opt->long_name, "exec"))
+			params.uprobes = true;
+#ifdef DWARF_SUPPORT
+		else if (!strcmp(opt->long_name, "module"))
+			params.uprobes = false;
+#endif
+		else
+			return ret;
+
+		params.target = str;
+		ret = 0;
+	}
+
+	return ret;
+}
+
 #ifdef DWARF_SUPPORT
 static int opt_show_lines(const struct option *opt __used,
 			  const char *str, int unset __used)
@@ -246,9 +270,9 @@ static const struct option options[] = {
 		   "file", "vmlinux pathname"),
 	OPT_STRING('s', "source", &symbol_conf.source_prefix,
 		   "directory", "path to kernel source"),
-	OPT_STRING('m', "module", &params.target,
-		   "modname|path",
-		   "target module name (for online) or path (for offline)"),
+	OPT_CALLBACK('m', "module", NULL, "modname|path",
+		"target module name (for online) or path (for offline)",
+		opt_set_target),
 #endif
 	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -260,6 +284,8 @@ static const struct option options[] = {
 		     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
 		     "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
 		     opt_set_filter),
+	OPT_CALLBACK('x', "exec", NULL, "executable|path",
+			"target executable name or path", opt_set_target),
 	OPT_END()
 };
 
@@ -310,6 +336,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			pr_err("  Error: Don't use --list with --funcs.\n");
 			usage_with_options(probe_usage, options);
 		}
+		if (params.uprobes) {
+			pr_warning("  Error: Don't use --list with --exec.\n");
+			usage_with_options(probe_usage, options);
+		}
 		ret = show_perf_probe_events();
 		if (ret < 0)
 			pr_err("  Error: Failed to show event list. (%d)\n",
@@ -333,8 +363,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		if (!params.filter)
 			params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
 						       NULL);
-		ret = show_available_funcs(params.target,
-					   params.filter);
+		ret = show_available_funcs(params.target, params.filter,
+					params.uprobes);
 		strfilter__delete(params.filter);
 		if (ret < 0)
 			pr_err("  Error: Failed to show functions."
@@ -343,7 +373,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 	}
 
 #ifdef DWARF_SUPPORT
-	if (params.show_lines) {
+	if (params.show_lines && !params.uprobes) {
 		if (params.mod_events) {
 			pr_err("  Error: Don't use --line with"
 			       " --add/--del.\n");
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8a8ee64..b7dec82 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -44,6 +44,7 @@
 #include "trace-event.h"	/* For __unused */
 #include "probe-event.h"
 #include "probe-finder.h"
+#include "session.h"
 
 #define MAX_CMDLEN 256
 #define MAX_PROBE_ARGS 128
@@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 }
 
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
+static int convert_name_to_addr(struct perf_probe_event *pev,
+				const char *exec);
 static struct machine machine;
 
 /* Initialize symbol maps and path of vmlinux/modules */
@@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module)
 	return (dso) ? dso->long_name : NULL;
 }
 
+static int init_user_exec(void)
+{
+	int ret = 0;
+
+	symbol_conf.try_vmlinux_path = false;
+	symbol_conf.sort_by_name = true;
+	ret = symbol__init();
+
+	if (ret < 0)
+		pr_debug("Failed to init symbol map.\n");
+
+	return ret;
+}
+
+static int convert_to_perf_probe_point(struct probe_trace_point *tp,
+					struct perf_probe_point *pp)
+{
+	pp->function = strdup(tp->symbol);
+
+	if (pp->function == NULL)
+		return -ENOMEM;
+
+	pp->offset = tp->offset;
+	pp->retprobe = tp->retprobe;
+
+	return 0;
+}
+
 #ifdef DWARF_SUPPORT
 /* Open new debuginfo of given module */
 static struct debuginfo *open_debuginfo(const char *module)
@@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 	if (ret <= 0) {
 		pr_debug("Failed to find corresponding probes from "
 			 "debuginfo. Use kprobe event information.\n");
-		pp->function = strdup(tp->symbol);
-		if (pp->function == NULL)
-			return -ENOMEM;
-		pp->offset = tp->offset;
+		return convert_to_perf_probe_point(tp, pp);
 	}
 	pp->retprobe = tp->retprobe;
 
@@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 					  int max_tevs, const char *target)
 {
 	bool need_dwarf = perf_probe_event_need_dwarf(pev);
-	struct debuginfo *dinfo = open_debuginfo(target);
+	struct debuginfo *dinfo;
 	int ntevs, ret = 0;
 
+	if (pev->uprobes) {
+		if (need_dwarf) {
+			pr_warning("Debuginfo-analysis is not yet supported"
+					" with -x/--exec option.\n");
+			return -ENOSYS;
+		}
+		return convert_name_to_addr(pev, target);
+	}
+
+	dinfo = open_debuginfo(target);
+
 	if (!dinfo) {
 		if (need_dwarf) {
 			pr_warning("Failed to open debuginfo file.\n");
@@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 		pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
 		return -ENOENT;
 	}
-	pp->function = strdup(tp->symbol);
-	if (pp->function == NULL)
-		return -ENOMEM;
-	pp->offset = tp->offset;
-	pp->retprobe = tp->retprobe;
 
-	return 0;
+	return convert_to_perf_probe_point(tp, pp);
 }
 
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 				struct probe_trace_event **tevs __unused,
-				int max_tevs __unused, const char *mod __unused)
+				int max_tevs __unused, const char *target)
 {
 	if (perf_probe_event_need_dwarf(pev)) {
 		pr_warning("Debuginfo-analysis is not supported.\n");
 		return -ENOSYS;
 	}
+
+	if (pev->uprobes)
+		return convert_name_to_addr(pev, target);
+
 	return 0;
 }
 
@@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
 	if (buf == NULL)
 		return NULL;
 
-	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
-			 tp->retprobe ? 'r' : 'p',
-			 tev->group, tev->event,
-			 tp->module ?: "", tp->module ? ":" : "",
-			 tp->symbol, tp->offset);
+	if (tev->uprobes)
+		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
+				 tp->retprobe ? 'r' : 'p',
+				 tev->group, tev->event,
+				 tp->module, tp->symbol);
+	else
+		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
+				 tp->retprobe ? 'r' : 'p',
+				 tev->group, tev->event,
+				 tp->module ?: "", tp->module ? ":" : "",
+				 tp->symbol, tp->offset);
+
 	if (len <= 0)
 		goto error;
 
@@ -1364,7 +1409,7 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
 }
 
 static int convert_to_perf_probe_event(struct probe_trace_event *tev,
-				       struct perf_probe_event *pev)
+			       struct perf_probe_event *pev, bool is_kprobe)
 {
 	char buf[64] = "";
 	int i, ret;
@@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
 		return -ENOMEM;
 
 	/* Convert trace_point to probe_point */
-	ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
+	if (is_kprobe)
+		ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
+	else
+		ret = convert_to_perf_probe_point(&tev->point, &pev->point);
+
 	if (ret < 0)
 		return ret;
 
@@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
 	memset(tev, 0, sizeof(*tev));
 }
 
-static int open_kprobe_events(bool readwrite)
+static void print_warn_msg(const char *file, bool is_kprobe)
+{
+
+	if (errno == ENOENT) {
+		const char *config;
+
+		if (!is_kprobe)
+			config = "CONFIG_UPROBE_EVENTS";
+		else
+			config = "CONFIG_KPROBE_EVENTS";
+
+		pr_warning("%s file does not exist - please rebuild kernel"
+				" with %s.\n", file, config);
+	} else
+		pr_warning("Failed to open %s file: %s\n", file,
+				strerror(errno));
+}
+
+static int open_probe_events(const char *trace_file, bool readwrite,
+				bool is_kprobe)
 {
 	char buf[PATH_MAX];
 	const char *__debugfs;
@@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite)
 		return -ENOENT;
 	}
 
-	ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
+	ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
 	if (ret >= 0) {
 		pr_debug("Opening %s write=%d\n", buf, readwrite);
 		if (readwrite && !probe_event_dry_run)
 			ret = open(buf, O_RDWR, O_APPEND);
 		else
 			ret = open(buf, O_RDONLY, 0);
-	}
 
-	if (ret < 0) {
-		if (errno == ENOENT)
-			pr_warning("kprobe_events file does not exist - please"
-				 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
-		else
-			pr_warning("Failed to open kprobe_events file: %s\n",
-				   strerror(errno));
+		if (ret < 0)
+			print_warn_msg(buf, is_kprobe);
 	}
 	return ret;
 }
 
-/* Get raw string list of current kprobe_events */
+static int open_kprobe_events(bool readwrite)
+{
+	return open_probe_events("tracing/kprobe_events", readwrite, true);
+}
+
+static int open_uprobe_events(bool readwrite)
+{
+	return open_probe_events("tracing/uprobe_events", readwrite, false);
+}
+
+/* Get raw string list of current kprobe_events  or uprobe_events */
 static struct strlist *get_probe_trace_command_rawlist(int fd)
 {
 	int ret, idx;
@@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
 	return ret;
 }
 
-/* List up current perf-probe events */
-int show_perf_probe_events(void)
+static int __show_perf_probe_events(int fd, bool is_kprobe)
 {
-	int fd, ret;
+	int ret = 0;
 	struct probe_trace_event tev;
 	struct perf_probe_event pev;
 	struct strlist *rawlist;
 	struct str_node *ent;
 
-	setup_pager();
-	ret = init_vmlinux();
-	if (ret < 0)
-		return ret;
-
 	memset(&tev, 0, sizeof(tev));
 	memset(&pev, 0, sizeof(pev));
 
-	fd = open_kprobe_events(false);
-	if (fd < 0)
-		return fd;
-
 	rawlist = get_probe_trace_command_rawlist(fd);
-	close(fd);
 	if (!rawlist)
 		return -ENOENT;
 
 	strlist__for_each(ent, rawlist) {
 		ret = parse_probe_trace_command(ent->s, &tev);
 		if (ret >= 0) {
-			ret = convert_to_perf_probe_event(&tev, &pev);
+			ret = convert_to_perf_probe_event(&tev, &pev,
+								is_kprobe);
 			if (ret >= 0)
 				ret = show_perf_probe_event(&pev);
 		}
@@ -1612,6 +1674,33 @@ int show_perf_probe_events(void)
 	return ret;
 }
 
+/* List up current perf-probe events */
+int show_perf_probe_events(void)
+{
+	int fd, ret;
+
+	setup_pager();
+	fd = open_kprobe_events(false);
+
+	if (fd < 0)
+		return fd;
+
+	ret = init_vmlinux();
+	if (ret < 0)
+		return ret;
+
+	ret = __show_perf_probe_events(fd, true);
+	close(fd);
+
+	fd = open_uprobe_events(false);
+	if (fd >= 0) {
+		ret = __show_perf_probe_events(fd, false);
+		close(fd);
+	}
+
+	return ret;
+}
+
 /* Get current perf-probe event names */
 static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
 {
@@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 	const char *event, *group;
 	struct strlist *namelist;
 
-	fd = open_kprobe_events(true);
+	if (pev->uprobes)
+		fd = open_uprobe_events(true);
+	else
+		fd = open_kprobe_events(true);
+
 	if (fd < 0)
 		return fd;
 	/* Get current event names */
@@ -1829,6 +1922,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 	tev->point.offset = pev->point.offset;
 	tev->point.retprobe = pev->point.retprobe;
 	tev->nargs = pev->nargs;
+	tev->uprobes = pev->uprobes;
 	if (tev->nargs) {
 		tev->args = zalloc(sizeof(struct probe_trace_arg)
 				   * tev->nargs);
@@ -1859,6 +1953,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 		}
 	}
 
+	if (pev->uprobes)
+		return 1;
+
 	/* Currently just checking function name from symbol map */
 	sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
 	if (!sym) {
@@ -1894,12 +1991,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
 	int i, j, ret;
 	struct __event_package *pkgs;
 
+	ret = 0;
 	pkgs = zalloc(sizeof(struct __event_package) * npevs);
+
 	if (pkgs == NULL)
 		return -ENOMEM;
 
-	/* Init vmlinux path */
-	ret = init_vmlinux();
+	if (!pevs->uprobes)
+		/* Init vmlinux path */
+		ret = init_vmlinux();
+	else
+		ret = init_user_exec();
+
 	if (ret < 0) {
 		free(pkgs);
 		return ret;
@@ -1971,23 +2074,15 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
 	return ret;
 }
 
-static int del_trace_probe_event(int fd, const char *group,
-				  const char *event, struct strlist *namelist)
+static int del_trace_probe_event(int fd, const char *buf,
+						  struct strlist *namelist)
 {
-	char buf[128];
 	struct str_node *ent, *n;
-	int found = 0, ret = 0;
-
-	ret = e_snprintf(buf, 128, "%s:%s", group, event);
-	if (ret < 0) {
-		pr_err("Failed to copy event.\n");
-		return ret;
-	}
+	int ret = -1;
 
 	if (strpbrk(buf, "*?")) { /* Glob-exp */
 		strlist__for_each_safe(ent, n, namelist)
 			if (strglobmatch(ent->s, buf)) {
-				found++;
 				ret = __del_trace_probe_event(fd, ent);
 				if (ret < 0)
 					break;
@@ -1996,40 +2091,43 @@ static int del_trace_probe_event(int fd, const char *group,
 	} else {
 		ent = strlist__find(namelist, buf);
 		if (ent) {
-			found++;
 			ret = __del_trace_probe_event(fd, ent);
 			if (ret >= 0)
 				strlist__remove(namelist, ent);
 		}
 	}
-	if (found == 0 && ret >= 0)
-		pr_info("Info: Event \"%s\" does not exist.\n", buf);
 
 	return ret;
 }
 
 int del_perf_probe_events(struct strlist *dellist)
 {
-	int fd, ret = 0;
+	int ret = -1, ufd = -1, kfd = -1;
+	char buf[128];
 	const char *group, *event;
 	char *p, *str;
 	struct str_node *ent;
-	struct strlist *namelist;
-
-	fd = open_kprobe_events(true);
-	if (fd < 0)
-		return fd;
+	struct strlist *namelist = NULL, *unamelist = NULL;
 
 	/* Get current event names */
-	namelist = get_probe_trace_event_names(fd, true);
-	if (namelist == NULL)
-		return -EINVAL;
+	kfd = open_kprobe_events(true);
+	if (kfd < 0)
+		return kfd;
+
+	namelist = get_probe_trace_event_names(kfd, true);
+	ufd = open_uprobe_events(true);
+
+	if (ufd >= 0)
+		unamelist = get_probe_trace_event_names(ufd, true);
+
+	if (namelist == NULL && unamelist == NULL)
+		goto error;
 
 	strlist__for_each(ent, dellist) {
 		str = strdup(ent->s);
 		if (str == NULL) {
 			ret = -ENOMEM;
-			break;
+			goto error;
 		}
 		pr_debug("Parsing: %s\n", str);
 		p = strchr(str, ':');
@@ -2041,17 +2139,46 @@ int del_perf_probe_events(struct strlist *dellist)
 			group = "*";
 			event = str;
 		}
+
+		ret = e_snprintf(buf, 128, "%s:%s", group, event);
+		if (ret < 0) {
+			pr_err("Failed to copy event.");
+			free(str);
+			goto error;
+		}
+
 		pr_debug("Group: %s, Event: %s\n", group, event);
-		ret = del_trace_probe_event(fd, group, event, namelist);
+
+		if (namelist)
+			ret = del_trace_probe_event(kfd, buf, namelist);
+
+		if (unamelist && ret != 0)
+			ret = del_trace_probe_event(ufd, buf, unamelist);
+
+		if (ret != 0)
+			pr_info("Info: Event \"%s\" does not exist.\n", buf);
+
 		free(str);
-		if (ret < 0)
-			break;
 	}
-	strlist__delete(namelist);
-	close(fd);
+
+error:
+	if (kfd >= 0) {
+		if (namelist)
+			strlist__delete(namelist);
+
+		close(kfd);
+	}
+
+	if (ufd >= 0) {
+		if (unamelist)
+			strlist__delete(unamelist);
+
+		close(ufd);
+	}
 
 	return ret;
 }
+
 /* TODO: don't use a global variable for filter ... */
 static struct strfilter *available_func_filter;
 
@@ -2068,30 +2195,157 @@ static int filter_available_functions(struct map *map __unused,
 	return 1;
 }
 
-int show_available_funcs(const char *target, struct strfilter *_filter)
+static int __show_available_funcs(struct map *map)
+{
+	if (map__load(map, filter_available_functions)) {
+		pr_err("Failed to load map.\n");
+		return -EINVAL;
+	}
+	if (!dso__sorted_by_name(map->dso, map->type))
+		dso__sort_by_name(map->dso, map->type);
+
+	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+	return 0;
+}
+
+static int available_kernel_funcs(const char *module)
 {
 	struct map *map;
 	int ret;
 
-	setup_pager();
-
 	ret = init_vmlinux();
 	if (ret < 0)
 		return ret;
 
-	map = kernel_get_module_map(target);
+	map = kernel_get_module_map(module);
 	if (!map) {
-		pr_err("Failed to find %s map.\n", (target) ? : "kernel");
+		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
 		return -EINVAL;
 	}
+	return __show_available_funcs(map);
+}
+
+static int available_user_funcs(const char *target)
+{
+	struct map *map;
+	int ret;
+
+	ret = init_user_exec();
+	if (ret < 0)
+		return ret;
+
+	map = dso__new_map(target);
+	ret = __show_available_funcs(map);
+	dso__delete(map->dso);
+	map__delete(map);
+	return ret;
+}
+
+int show_available_funcs(const char *target, struct strfilter *_filter,
+					bool user)
+{
+	setup_pager();
 	available_func_filter = _filter;
+
+	if (!user)
+		return available_kernel_funcs(target);
+
+	return available_user_funcs(target);
+}
+
+/*
+ * uprobe_events only accepts address:
+ * Convert function and any offset to address
+ */
+static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
+{
+	struct perf_probe_point *pp = &pev->point;
+	struct symbol *sym;
+	struct map *map = NULL;
+	char *function = NULL, *name = NULL;
+	int ret = -EINVAL;
+	unsigned long long vaddr = 0;
+
+	if (!pp->function) {
+		pr_warning("No function specified for uprobes");
+		goto out;
+	}
+
+	if (perf_probe_event_need_dwarf(pev)) {
+		pr_warning("No dwarf based probes for uprobes.");
+		goto out;
+	}
+
+	function = strdup(pp->function);
+	if (!function) {
+		pr_warning("Failed to allocate memory by strdup.\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	name = realpath(exec, NULL);
+	if (!name) {
+		pr_warning("Cannot find realpath for %s.\n", exec);
+		goto out;
+	}
+	map = dso__new_map(name);
+	if (!map) {
+		pr_warning("Cannot find appropriate DSO for %s.\n", exec);
+		goto out;
+	}
+	available_func_filter = strfilter__new(function, NULL);
 	if (map__load(map, filter_available_functions)) {
 		pr_err("Failed to load map.\n");
 		return -EINVAL;
 	}
-	if (!dso__sorted_by_name(map->dso, map->type))
-		dso__sort_by_name(map->dso, map->type);
 
-	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
-	return 0;
+	sym = map__find_symbol_by_name(map, function, NULL);
+	if (!sym) {
+		pr_warning("Cannot find %s in DSO %s\n", function, exec);
+		goto out;
+	}
+
+	if (map->start > sym->start)
+		vaddr = map->start;
+	vaddr += sym->start + pp->offset + map->pgoff;
+	pp->offset = 0;
+
+	if (!pev->event) {
+		pev->event = function;
+		function = NULL;
+	}
+	if (!pev->group) {
+		char *ptr1, *ptr2;
+
+		pev->group = zalloc(sizeof(char *) * 64);
+		ptr1 = strdup(basename(exec));
+		if (ptr1) {
+			ptr2 = strpbrk(ptr1, "-._");
+			if (ptr2)
+				*ptr2 = '\0';
+			e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
+					ptr1);
+			free(ptr1);
+		}
+	}
+	free(pp->function);
+	pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
+	if (!pp->function) {
+		ret = -ENOMEM;
+		pr_warning("Failed to allocate memory by zalloc.\n");
+		goto out;
+	}
+	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
+	ret = 0;
+
+out:
+	if (map) {
+		dso__delete(map->dso);
+		map__delete(map);
+	}
+	if (function)
+		free(function);
+	if (name)
+		free(name);
+	return ret;
 }
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index a7dee83..f9f3de8 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -7,7 +7,7 @@
 
 extern bool probe_event_dry_run;
 
-/* kprobe-tracer tracing point */
+/* kprobe-tracer and uprobe-tracer tracing point */
 struct probe_trace_point {
 	char		*symbol;	/* Base symbol */
 	char		*module;	/* Module name */
@@ -21,7 +21,7 @@ struct probe_trace_arg_ref {
 	long				offset;	/* Offset value */
 };
 
-/* kprobe-tracer tracing argument */
+/* kprobe-tracer and uprobe-tracer tracing argument */
 struct probe_trace_arg {
 	char				*name;	/* Argument name */
 	char				*value;	/* Base value */
@@ -29,12 +29,13 @@ struct probe_trace_arg {
 	struct probe_trace_arg_ref	*ref;	/* Referencing offset */
 };
 
-/* kprobe-tracer tracing event (point + arg) */
+/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */
 struct probe_trace_event {
 	char				*event;	/* Event name */
 	char				*group;	/* Group name */
 	struct probe_trace_point	point;	/* Trace point */
 	int				nargs;	/* Number of args */
+	bool				uprobes;	/* uprobes only */
 	struct probe_trace_arg		*args;	/* Arguments */
 };
 
@@ -70,6 +71,7 @@ struct perf_probe_event {
 	char			*group;	/* Group name */
 	struct perf_probe_point	point;	/* Probe point */
 	int			nargs;	/* Number of arguments */
+	bool			uprobes;
 	struct perf_probe_arg	*args;	/* Arguments */
 };
 
@@ -129,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
 			       int max_probe_points, const char *module,
 			       struct strfilter *filter, bool externs);
-extern int show_available_funcs(const char *module, struct strfilter *filter);
-
+extern int show_available_funcs(const char *module, struct strfilter *filter,
+				bool user);
 
 /* Maximum index number of event-name postfix */
 #define MAX_EVENT_INDEX	1024
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c0a028c..caaf75a 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -2784,3 +2784,11 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
 
 	return ret;
 }
+
+struct map *dso__new_map(const char *name)
+{
+	struct dso *dso = dso__new(name);
+	struct map *map = map__new2(0, dso, MAP__FUNCTION);
+
+	return map;
+}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ac49ef2..9e7742c 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -237,6 +237,7 @@ void dso__set_long_name(struct dso *dso, char *name);
 void dso__set_build_id(struct dso *dso, void *build_id);
 void dso__read_running_kernel_build_id(struct dso *dso,
 				       struct machine *machine);
+struct map *dso__new_map(const char *name);
 struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
 				u64 addr);
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-11 13:57 ` Srikar Dronamraju
  0 siblings, 0 replies; 24+ messages in thread
From: Srikar Dronamraju @ 2012-04-11 13:57 UTC (permalink / raw)
  To: Peter Zijlstra, Ingo Molnar
  Cc: Andrew Morton, Linus Torvalds, Ananth N Mavinakayanahalli,
	Jim Keniston, LKML, Linux-mm, Oleg Nesterov, Andi Kleen,
	Christoph Hellwig, Steven Rostedt, Arnaldo Carvalho de Melo,
	Masami Hiramatsu, Thomas Gleixner, Anton Arapov

From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>

- Enhances perf to probe user space executables and libraries.
- Enhances -F/--funcs option of "perf probe" to list possible probe points in
  an executable file or library.
- Documents userspace probing support in perf.

[ Probing a function in the executable using function name  ]
perf probe -x /bin/zsh zfree

[ Probing a library function using function name ]
perf probe -x /lib64/libc.so.6 malloc

[ list probe-able functions in an executable ]
perf probe -F -x /bin/zsh

[ list probe-able functions in an library]
perf probe -F -x /lib/libc.so.6

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

Changelog:
(v9)
- Handled comments from Masami Hiramatsu that helps reduce code changes.
- Handled usability comment(print complete name of file) from Ingo Molnar.

(v5)
- Removed the separate documentation change patch and added the
  documentation changes as part of this patch.

Usage:
[root@localhost ~]# perf probe -x /bin/zsh zfree
Add new event:
  probe_zsh:zfree      (on /bin/zsh:0x45400)

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

	perf record -e probe_zsh:zfree -aR sleep 1

[root@localhost ~]# perf record -e probe_zsh:zfree -aR sleep 15
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.314 MB perf.data (~13715 samples) ]
[root@localhost ~]# perf report --stdio
# Events: 3K probe_zsh:zfree
#
# Overhead  Command  Shared Object  Symbol
# ........  .......  .............  ......
#
   100.00%              zsh  zsh            [.] zfree


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

[ Probing a library function using function name ]
--------------------------------------------------
[root@localhost]#
[root@localhost]# perf probe -x /lib64/libc.so.6 malloc
Add new event:
  probe_libc:malloc    (on /lib64/libc-2.5.so:0x74dc0)

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

	perf record -e probe_libc:malloc -aR sleep 1

[root@localhost]#
[root@localhost]# perf probe --list
  probe_libc:malloc    (on /lib64/libc-2.5.so:0x0000000000074dc0)


Show last 10 functions in /bin/zsh.

# perf probe -F -x /bin/zsh | tail
zstrtol
ztrcmp
ztrdup
ztrduppfx
ztrftime
ztrlen
ztrncpy
ztrsub
zwarn
zwarnnam

Show first 10 functions in /lib/libc.so.6

# perf probe -F -x /lib/libc.so.6 | head
_IO_adjust_column
_IO_adjust_wcolumn
_IO_default_doallocate
_IO_default_finish
_IO_default_pbackfail
_IO_default_uflow
_IO_default_xsgetn
_IO_default_xsputn
_IO_do_write@@GLIBC_2.2.5
_IO_doallocbuf

 tools/perf/Documentation/perf-probe.txt |   15 +
 tools/perf/builtin-probe.c              |   42 +++
 tools/perf/util/probe-event.c           |  424 +++++++++++++++++++++++++------
 tools/perf/util/probe-event.h           |   12 +
 tools/perf/util/symbol.c                |    8 +
 tools/perf/util/symbol.h                |    1 
 6 files changed, 405 insertions(+), 97 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 2780d9c..fb673be 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -77,7 +77,8 @@ OPTIONS
 
 -F::
 --funcs::
-	Show available functions in given module or kernel.
+	Show available functions in given module or kernel. With -x/--exec,
+	can also list functions in a user space executable / shared library.
 
 --filter=FILTER::
 	(Only for --vars and --funcs) Set filter. FILTER is a combination of glob
@@ -98,6 +99,11 @@ OPTIONS
 --max-probes::
 	Set the maximum number of probe points for an event. Default is 128.
 
+-x::
+--exec=PATH::
+	Specify path to the executable or shared library file for user
+	space tracing. Can also be used with --funcs option.
+
 PROBE SYNTAX
 ------------
 Probe points are defined by following syntax.
@@ -182,6 +188,13 @@ Delete all probes on schedule().
 
  ./perf probe --del='schedule*'
 
+Add probes at zfree() function on /bin/zsh
+
+ ./perf probe -x /bin/zsh zfree
+
+Add probes at malloc() function on libc
+
+ ./perf probe -x /lib/libc.so.6 malloc
 
 SEE ALSO
 --------
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 4935c09..c1bf0d8 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -54,6 +54,7 @@ static struct {
 	bool show_ext_vars;
 	bool show_funcs;
 	bool mod_events;
+	bool uprobes;
 	int nevents;
 	struct perf_probe_event events[MAX_PROBES];
 	struct strlist *dellist;
@@ -75,6 +76,7 @@ static int parse_probe_event(const char *str)
 		return -1;
 	}
 
+	pev->uprobes = params.uprobes;
 	/* Parse a perf-probe command into event */
 	ret = parse_perf_probe_command(str, pev);
 	pr_debug("%d arguments\n", pev->nargs);
@@ -125,6 +127,28 @@ static int opt_del_probe_event(const struct option *opt __used,
 	return 0;
 }
 
+static int opt_set_target(const struct option *opt, const char *str,
+			int unset __used)
+{
+	int ret = -ENOENT;
+
+	if  (str && !params.target) {
+		if (!strcmp(opt->long_name, "exec"))
+			params.uprobes = true;
+#ifdef DWARF_SUPPORT
+		else if (!strcmp(opt->long_name, "module"))
+			params.uprobes = false;
+#endif
+		else
+			return ret;
+
+		params.target = str;
+		ret = 0;
+	}
+
+	return ret;
+}
+
 #ifdef DWARF_SUPPORT
 static int opt_show_lines(const struct option *opt __used,
 			  const char *str, int unset __used)
@@ -246,9 +270,9 @@ static const struct option options[] = {
 		   "file", "vmlinux pathname"),
 	OPT_STRING('s', "source", &symbol_conf.source_prefix,
 		   "directory", "path to kernel source"),
-	OPT_STRING('m', "module", &params.target,
-		   "modname|path",
-		   "target module name (for online) or path (for offline)"),
+	OPT_CALLBACK('m', "module", NULL, "modname|path",
+		"target module name (for online) or path (for offline)",
+		opt_set_target),
 #endif
 	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -260,6 +284,8 @@ static const struct option options[] = {
 		     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
 		     "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
 		     opt_set_filter),
+	OPT_CALLBACK('x', "exec", NULL, "executable|path",
+			"target executable name or path", opt_set_target),
 	OPT_END()
 };
 
@@ -310,6 +336,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			pr_err("  Error: Don't use --list with --funcs.\n");
 			usage_with_options(probe_usage, options);
 		}
+		if (params.uprobes) {
+			pr_warning("  Error: Don't use --list with --exec.\n");
+			usage_with_options(probe_usage, options);
+		}
 		ret = show_perf_probe_events();
 		if (ret < 0)
 			pr_err("  Error: Failed to show event list. (%d)\n",
@@ -333,8 +363,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		if (!params.filter)
 			params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
 						       NULL);
-		ret = show_available_funcs(params.target,
-					   params.filter);
+		ret = show_available_funcs(params.target, params.filter,
+					params.uprobes);
 		strfilter__delete(params.filter);
 		if (ret < 0)
 			pr_err("  Error: Failed to show functions."
@@ -343,7 +373,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 	}
 
 #ifdef DWARF_SUPPORT
-	if (params.show_lines) {
+	if (params.show_lines && !params.uprobes) {
 		if (params.mod_events) {
 			pr_err("  Error: Don't use --line with"
 			       " --add/--del.\n");
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8a8ee64..b7dec82 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -44,6 +44,7 @@
 #include "trace-event.h"	/* For __unused */
 #include "probe-event.h"
 #include "probe-finder.h"
+#include "session.h"
 
 #define MAX_CMDLEN 256
 #define MAX_PROBE_ARGS 128
@@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 }
 
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
+static int convert_name_to_addr(struct perf_probe_event *pev,
+				const char *exec);
 static struct machine machine;
 
 /* Initialize symbol maps and path of vmlinux/modules */
@@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module)
 	return (dso) ? dso->long_name : NULL;
 }
 
+static int init_user_exec(void)
+{
+	int ret = 0;
+
+	symbol_conf.try_vmlinux_path = false;
+	symbol_conf.sort_by_name = true;
+	ret = symbol__init();
+
+	if (ret < 0)
+		pr_debug("Failed to init symbol map.\n");
+
+	return ret;
+}
+
+static int convert_to_perf_probe_point(struct probe_trace_point *tp,
+					struct perf_probe_point *pp)
+{
+	pp->function = strdup(tp->symbol);
+
+	if (pp->function == NULL)
+		return -ENOMEM;
+
+	pp->offset = tp->offset;
+	pp->retprobe = tp->retprobe;
+
+	return 0;
+}
+
 #ifdef DWARF_SUPPORT
 /* Open new debuginfo of given module */
 static struct debuginfo *open_debuginfo(const char *module)
@@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 	if (ret <= 0) {
 		pr_debug("Failed to find corresponding probes from "
 			 "debuginfo. Use kprobe event information.\n");
-		pp->function = strdup(tp->symbol);
-		if (pp->function == NULL)
-			return -ENOMEM;
-		pp->offset = tp->offset;
+		return convert_to_perf_probe_point(tp, pp);
 	}
 	pp->retprobe = tp->retprobe;
 
@@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 					  int max_tevs, const char *target)
 {
 	bool need_dwarf = perf_probe_event_need_dwarf(pev);
-	struct debuginfo *dinfo = open_debuginfo(target);
+	struct debuginfo *dinfo;
 	int ntevs, ret = 0;
 
+	if (pev->uprobes) {
+		if (need_dwarf) {
+			pr_warning("Debuginfo-analysis is not yet supported"
+					" with -x/--exec option.\n");
+			return -ENOSYS;
+		}
+		return convert_name_to_addr(pev, target);
+	}
+
+	dinfo = open_debuginfo(target);
+
 	if (!dinfo) {
 		if (need_dwarf) {
 			pr_warning("Failed to open debuginfo file.\n");
@@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 		pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
 		return -ENOENT;
 	}
-	pp->function = strdup(tp->symbol);
-	if (pp->function == NULL)
-		return -ENOMEM;
-	pp->offset = tp->offset;
-	pp->retprobe = tp->retprobe;
 
-	return 0;
+	return convert_to_perf_probe_point(tp, pp);
 }
 
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 				struct probe_trace_event **tevs __unused,
-				int max_tevs __unused, const char *mod __unused)
+				int max_tevs __unused, const char *target)
 {
 	if (perf_probe_event_need_dwarf(pev)) {
 		pr_warning("Debuginfo-analysis is not supported.\n");
 		return -ENOSYS;
 	}
+
+	if (pev->uprobes)
+		return convert_name_to_addr(pev, target);
+
 	return 0;
 }
 
@@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
 	if (buf == NULL)
 		return NULL;
 
-	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
-			 tp->retprobe ? 'r' : 'p',
-			 tev->group, tev->event,
-			 tp->module ?: "", tp->module ? ":" : "",
-			 tp->symbol, tp->offset);
+	if (tev->uprobes)
+		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
+				 tp->retprobe ? 'r' : 'p',
+				 tev->group, tev->event,
+				 tp->module, tp->symbol);
+	else
+		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
+				 tp->retprobe ? 'r' : 'p',
+				 tev->group, tev->event,
+				 tp->module ?: "", tp->module ? ":" : "",
+				 tp->symbol, tp->offset);
+
 	if (len <= 0)
 		goto error;
 
@@ -1364,7 +1409,7 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
 }
 
 static int convert_to_perf_probe_event(struct probe_trace_event *tev,
-				       struct perf_probe_event *pev)
+			       struct perf_probe_event *pev, bool is_kprobe)
 {
 	char buf[64] = "";
 	int i, ret;
@@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
 		return -ENOMEM;
 
 	/* Convert trace_point to probe_point */
-	ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
+	if (is_kprobe)
+		ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
+	else
+		ret = convert_to_perf_probe_point(&tev->point, &pev->point);
+
 	if (ret < 0)
 		return ret;
 
@@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
 	memset(tev, 0, sizeof(*tev));
 }
 
-static int open_kprobe_events(bool readwrite)
+static void print_warn_msg(const char *file, bool is_kprobe)
+{
+
+	if (errno == ENOENT) {
+		const char *config;
+
+		if (!is_kprobe)
+			config = "CONFIG_UPROBE_EVENTS";
+		else
+			config = "CONFIG_KPROBE_EVENTS";
+
+		pr_warning("%s file does not exist - please rebuild kernel"
+				" with %s.\n", file, config);
+	} else
+		pr_warning("Failed to open %s file: %s\n", file,
+				strerror(errno));
+}
+
+static int open_probe_events(const char *trace_file, bool readwrite,
+				bool is_kprobe)
 {
 	char buf[PATH_MAX];
 	const char *__debugfs;
@@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite)
 		return -ENOENT;
 	}
 
-	ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
+	ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
 	if (ret >= 0) {
 		pr_debug("Opening %s write=%d\n", buf, readwrite);
 		if (readwrite && !probe_event_dry_run)
 			ret = open(buf, O_RDWR, O_APPEND);
 		else
 			ret = open(buf, O_RDONLY, 0);
-	}
 
-	if (ret < 0) {
-		if (errno == ENOENT)
-			pr_warning("kprobe_events file does not exist - please"
-				 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
-		else
-			pr_warning("Failed to open kprobe_events file: %s\n",
-				   strerror(errno));
+		if (ret < 0)
+			print_warn_msg(buf, is_kprobe);
 	}
 	return ret;
 }
 
-/* Get raw string list of current kprobe_events */
+static int open_kprobe_events(bool readwrite)
+{
+	return open_probe_events("tracing/kprobe_events", readwrite, true);
+}
+
+static int open_uprobe_events(bool readwrite)
+{
+	return open_probe_events("tracing/uprobe_events", readwrite, false);
+}
+
+/* Get raw string list of current kprobe_events  or uprobe_events */
 static struct strlist *get_probe_trace_command_rawlist(int fd)
 {
 	int ret, idx;
@@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
 	return ret;
 }
 
-/* List up current perf-probe events */
-int show_perf_probe_events(void)
+static int __show_perf_probe_events(int fd, bool is_kprobe)
 {
-	int fd, ret;
+	int ret = 0;
 	struct probe_trace_event tev;
 	struct perf_probe_event pev;
 	struct strlist *rawlist;
 	struct str_node *ent;
 
-	setup_pager();
-	ret = init_vmlinux();
-	if (ret < 0)
-		return ret;
-
 	memset(&tev, 0, sizeof(tev));
 	memset(&pev, 0, sizeof(pev));
 
-	fd = open_kprobe_events(false);
-	if (fd < 0)
-		return fd;
-
 	rawlist = get_probe_trace_command_rawlist(fd);
-	close(fd);
 	if (!rawlist)
 		return -ENOENT;
 
 	strlist__for_each(ent, rawlist) {
 		ret = parse_probe_trace_command(ent->s, &tev);
 		if (ret >= 0) {
-			ret = convert_to_perf_probe_event(&tev, &pev);
+			ret = convert_to_perf_probe_event(&tev, &pev,
+								is_kprobe);
 			if (ret >= 0)
 				ret = show_perf_probe_event(&pev);
 		}
@@ -1612,6 +1674,33 @@ int show_perf_probe_events(void)
 	return ret;
 }
 
+/* List up current perf-probe events */
+int show_perf_probe_events(void)
+{
+	int fd, ret;
+
+	setup_pager();
+	fd = open_kprobe_events(false);
+
+	if (fd < 0)
+		return fd;
+
+	ret = init_vmlinux();
+	if (ret < 0)
+		return ret;
+
+	ret = __show_perf_probe_events(fd, true);
+	close(fd);
+
+	fd = open_uprobe_events(false);
+	if (fd >= 0) {
+		ret = __show_perf_probe_events(fd, false);
+		close(fd);
+	}
+
+	return ret;
+}
+
 /* Get current perf-probe event names */
 static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
 {
@@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 	const char *event, *group;
 	struct strlist *namelist;
 
-	fd = open_kprobe_events(true);
+	if (pev->uprobes)
+		fd = open_uprobe_events(true);
+	else
+		fd = open_kprobe_events(true);
+
 	if (fd < 0)
 		return fd;
 	/* Get current event names */
@@ -1829,6 +1922,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 	tev->point.offset = pev->point.offset;
 	tev->point.retprobe = pev->point.retprobe;
 	tev->nargs = pev->nargs;
+	tev->uprobes = pev->uprobes;
 	if (tev->nargs) {
 		tev->args = zalloc(sizeof(struct probe_trace_arg)
 				   * tev->nargs);
@@ -1859,6 +1953,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 		}
 	}
 
+	if (pev->uprobes)
+		return 1;
+
 	/* Currently just checking function name from symbol map */
 	sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
 	if (!sym) {
@@ -1894,12 +1991,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
 	int i, j, ret;
 	struct __event_package *pkgs;
 
+	ret = 0;
 	pkgs = zalloc(sizeof(struct __event_package) * npevs);
+
 	if (pkgs == NULL)
 		return -ENOMEM;
 
-	/* Init vmlinux path */
-	ret = init_vmlinux();
+	if (!pevs->uprobes)
+		/* Init vmlinux path */
+		ret = init_vmlinux();
+	else
+		ret = init_user_exec();
+
 	if (ret < 0) {
 		free(pkgs);
 		return ret;
@@ -1971,23 +2074,15 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
 	return ret;
 }
 
-static int del_trace_probe_event(int fd, const char *group,
-				  const char *event, struct strlist *namelist)
+static int del_trace_probe_event(int fd, const char *buf,
+						  struct strlist *namelist)
 {
-	char buf[128];
 	struct str_node *ent, *n;
-	int found = 0, ret = 0;
-
-	ret = e_snprintf(buf, 128, "%s:%s", group, event);
-	if (ret < 0) {
-		pr_err("Failed to copy event.\n");
-		return ret;
-	}
+	int ret = -1;
 
 	if (strpbrk(buf, "*?")) { /* Glob-exp */
 		strlist__for_each_safe(ent, n, namelist)
 			if (strglobmatch(ent->s, buf)) {
-				found++;
 				ret = __del_trace_probe_event(fd, ent);
 				if (ret < 0)
 					break;
@@ -1996,40 +2091,43 @@ static int del_trace_probe_event(int fd, const char *group,
 	} else {
 		ent = strlist__find(namelist, buf);
 		if (ent) {
-			found++;
 			ret = __del_trace_probe_event(fd, ent);
 			if (ret >= 0)
 				strlist__remove(namelist, ent);
 		}
 	}
-	if (found == 0 && ret >= 0)
-		pr_info("Info: Event \"%s\" does not exist.\n", buf);
 
 	return ret;
 }
 
 int del_perf_probe_events(struct strlist *dellist)
 {
-	int fd, ret = 0;
+	int ret = -1, ufd = -1, kfd = -1;
+	char buf[128];
 	const char *group, *event;
 	char *p, *str;
 	struct str_node *ent;
-	struct strlist *namelist;
-
-	fd = open_kprobe_events(true);
-	if (fd < 0)
-		return fd;
+	struct strlist *namelist = NULL, *unamelist = NULL;
 
 	/* Get current event names */
-	namelist = get_probe_trace_event_names(fd, true);
-	if (namelist == NULL)
-		return -EINVAL;
+	kfd = open_kprobe_events(true);
+	if (kfd < 0)
+		return kfd;
+
+	namelist = get_probe_trace_event_names(kfd, true);
+	ufd = open_uprobe_events(true);
+
+	if (ufd >= 0)
+		unamelist = get_probe_trace_event_names(ufd, true);
+
+	if (namelist == NULL && unamelist == NULL)
+		goto error;
 
 	strlist__for_each(ent, dellist) {
 		str = strdup(ent->s);
 		if (str == NULL) {
 			ret = -ENOMEM;
-			break;
+			goto error;
 		}
 		pr_debug("Parsing: %s\n", str);
 		p = strchr(str, ':');
@@ -2041,17 +2139,46 @@ int del_perf_probe_events(struct strlist *dellist)
 			group = "*";
 			event = str;
 		}
+
+		ret = e_snprintf(buf, 128, "%s:%s", group, event);
+		if (ret < 0) {
+			pr_err("Failed to copy event.");
+			free(str);
+			goto error;
+		}
+
 		pr_debug("Group: %s, Event: %s\n", group, event);
-		ret = del_trace_probe_event(fd, group, event, namelist);
+
+		if (namelist)
+			ret = del_trace_probe_event(kfd, buf, namelist);
+
+		if (unamelist && ret != 0)
+			ret = del_trace_probe_event(ufd, buf, unamelist);
+
+		if (ret != 0)
+			pr_info("Info: Event \"%s\" does not exist.\n", buf);
+
 		free(str);
-		if (ret < 0)
-			break;
 	}
-	strlist__delete(namelist);
-	close(fd);
+
+error:
+	if (kfd >= 0) {
+		if (namelist)
+			strlist__delete(namelist);
+
+		close(kfd);
+	}
+
+	if (ufd >= 0) {
+		if (unamelist)
+			strlist__delete(unamelist);
+
+		close(ufd);
+	}
 
 	return ret;
 }
+
 /* TODO: don't use a global variable for filter ... */
 static struct strfilter *available_func_filter;
 
@@ -2068,30 +2195,157 @@ static int filter_available_functions(struct map *map __unused,
 	return 1;
 }
 
-int show_available_funcs(const char *target, struct strfilter *_filter)
+static int __show_available_funcs(struct map *map)
+{
+	if (map__load(map, filter_available_functions)) {
+		pr_err("Failed to load map.\n");
+		return -EINVAL;
+	}
+	if (!dso__sorted_by_name(map->dso, map->type))
+		dso__sort_by_name(map->dso, map->type);
+
+	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+	return 0;
+}
+
+static int available_kernel_funcs(const char *module)
 {
 	struct map *map;
 	int ret;
 
-	setup_pager();
-
 	ret = init_vmlinux();
 	if (ret < 0)
 		return ret;
 
-	map = kernel_get_module_map(target);
+	map = kernel_get_module_map(module);
 	if (!map) {
-		pr_err("Failed to find %s map.\n", (target) ? : "kernel");
+		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
 		return -EINVAL;
 	}
+	return __show_available_funcs(map);
+}
+
+static int available_user_funcs(const char *target)
+{
+	struct map *map;
+	int ret;
+
+	ret = init_user_exec();
+	if (ret < 0)
+		return ret;
+
+	map = dso__new_map(target);
+	ret = __show_available_funcs(map);
+	dso__delete(map->dso);
+	map__delete(map);
+	return ret;
+}
+
+int show_available_funcs(const char *target, struct strfilter *_filter,
+					bool user)
+{
+	setup_pager();
 	available_func_filter = _filter;
+
+	if (!user)
+		return available_kernel_funcs(target);
+
+	return available_user_funcs(target);
+}
+
+/*
+ * uprobe_events only accepts address:
+ * Convert function and any offset to address
+ */
+static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
+{
+	struct perf_probe_point *pp = &pev->point;
+	struct symbol *sym;
+	struct map *map = NULL;
+	char *function = NULL, *name = NULL;
+	int ret = -EINVAL;
+	unsigned long long vaddr = 0;
+
+	if (!pp->function) {
+		pr_warning("No function specified for uprobes");
+		goto out;
+	}
+
+	if (perf_probe_event_need_dwarf(pev)) {
+		pr_warning("No dwarf based probes for uprobes.");
+		goto out;
+	}
+
+	function = strdup(pp->function);
+	if (!function) {
+		pr_warning("Failed to allocate memory by strdup.\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	name = realpath(exec, NULL);
+	if (!name) {
+		pr_warning("Cannot find realpath for %s.\n", exec);
+		goto out;
+	}
+	map = dso__new_map(name);
+	if (!map) {
+		pr_warning("Cannot find appropriate DSO for %s.\n", exec);
+		goto out;
+	}
+	available_func_filter = strfilter__new(function, NULL);
 	if (map__load(map, filter_available_functions)) {
 		pr_err("Failed to load map.\n");
 		return -EINVAL;
 	}
-	if (!dso__sorted_by_name(map->dso, map->type))
-		dso__sort_by_name(map->dso, map->type);
 
-	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
-	return 0;
+	sym = map__find_symbol_by_name(map, function, NULL);
+	if (!sym) {
+		pr_warning("Cannot find %s in DSO %s\n", function, exec);
+		goto out;
+	}
+
+	if (map->start > sym->start)
+		vaddr = map->start;
+	vaddr += sym->start + pp->offset + map->pgoff;
+	pp->offset = 0;
+
+	if (!pev->event) {
+		pev->event = function;
+		function = NULL;
+	}
+	if (!pev->group) {
+		char *ptr1, *ptr2;
+
+		pev->group = zalloc(sizeof(char *) * 64);
+		ptr1 = strdup(basename(exec));
+		if (ptr1) {
+			ptr2 = strpbrk(ptr1, "-._");
+			if (ptr2)
+				*ptr2 = '\0';
+			e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
+					ptr1);
+			free(ptr1);
+		}
+	}
+	free(pp->function);
+	pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
+	if (!pp->function) {
+		ret = -ENOMEM;
+		pr_warning("Failed to allocate memory by zalloc.\n");
+		goto out;
+	}
+	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
+	ret = 0;
+
+out:
+	if (map) {
+		dso__delete(map->dso);
+		map__delete(map);
+	}
+	if (function)
+		free(function);
+	if (name)
+		free(name);
+	return ret;
 }
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index a7dee83..f9f3de8 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -7,7 +7,7 @@
 
 extern bool probe_event_dry_run;
 
-/* kprobe-tracer tracing point */
+/* kprobe-tracer and uprobe-tracer tracing point */
 struct probe_trace_point {
 	char		*symbol;	/* Base symbol */
 	char		*module;	/* Module name */
@@ -21,7 +21,7 @@ struct probe_trace_arg_ref {
 	long				offset;	/* Offset value */
 };
 
-/* kprobe-tracer tracing argument */
+/* kprobe-tracer and uprobe-tracer tracing argument */
 struct probe_trace_arg {
 	char				*name;	/* Argument name */
 	char				*value;	/* Base value */
@@ -29,12 +29,13 @@ struct probe_trace_arg {
 	struct probe_trace_arg_ref	*ref;	/* Referencing offset */
 };
 
-/* kprobe-tracer tracing event (point + arg) */
+/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */
 struct probe_trace_event {
 	char				*event;	/* Event name */
 	char				*group;	/* Group name */
 	struct probe_trace_point	point;	/* Trace point */
 	int				nargs;	/* Number of args */
+	bool				uprobes;	/* uprobes only */
 	struct probe_trace_arg		*args;	/* Arguments */
 };
 
@@ -70,6 +71,7 @@ struct perf_probe_event {
 	char			*group;	/* Group name */
 	struct perf_probe_point	point;	/* Probe point */
 	int			nargs;	/* Number of arguments */
+	bool			uprobes;
 	struct perf_probe_arg	*args;	/* Arguments */
 };
 
@@ -129,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
 			       int max_probe_points, const char *module,
 			       struct strfilter *filter, bool externs);
-extern int show_available_funcs(const char *module, struct strfilter *filter);
-
+extern int show_available_funcs(const char *module, struct strfilter *filter,
+				bool user);
 
 /* Maximum index number of event-name postfix */
 #define MAX_EVENT_INDEX	1024
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c0a028c..caaf75a 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -2784,3 +2784,11 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
 
 	return ret;
 }
+
+struct map *dso__new_map(const char *name)
+{
+	struct dso *dso = dso__new(name);
+	struct map *map = map__new2(0, dso, MAP__FUNCTION);
+
+	return map;
+}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ac49ef2..9e7742c 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -237,6 +237,7 @@ void dso__set_long_name(struct dso *dso, char *name);
 void dso__set_build_id(struct dso *dso, void *build_id);
 void dso__read_running_kernel_build_id(struct dso *dso,
 				       struct machine *machine);
+struct map *dso__new_map(const char *name);
 struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
 				u64 addr);
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,


--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH] perf/probe: Provide perf interface for uprobes
  2012-04-11 13:57 ` Srikar Dronamraju
@ 2012-04-11 14:49   ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-04-11 14:49 UTC (permalink / raw)
  To: Srikar Dronamraju
  Cc: Peter Zijlstra, Ingo Molnar, Andrew Morton, Linus Torvalds,
	Ananth N Mavinakayanahalli, Jim Keniston, LKML, Linux-mm,
	Oleg Nesterov, Andi Kleen, Christoph Hellwig, Steven Rostedt,
	Masami Hiramatsu, Thomas Gleixner, Anton Arapov

Em Wed, Apr 11, 2012 at 07:27:42PM +0530, Srikar Dronamraju escreveu:
> From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
> 
> - Enhances perf to probe user space executables and libraries.
> - Enhances -F/--funcs option of "perf probe" to list possible probe points in
>   an executable file or library.
> - Documents userspace probing support in perf.
> 
> [ Probing a function in the executable using function name  ]
> perf probe -x /bin/zsh zfree
> 
> [ Probing a library function using function name ]
> perf probe -x /lib64/libc.so.6 malloc
> 
> [ list probe-able functions in an executable ]
> perf probe -F -x /bin/zsh
> 
> [ list probe-able functions in an library]
> perf probe -F -x /lib/libc.so.6

Can we avoid the need for -x? I.e. we could figure out it is userspace
and act accordingly.

- Arnaldo
 
> Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
> ---
> 
> Changelog:
> (v9)
> - Handled comments from Masami Hiramatsu that helps reduce code changes.
> - Handled usability comment(print complete name of file) from Ingo Molnar.
> 
> (v5)
> - Removed the separate documentation change patch and added the
>   documentation changes as part of this patch.
> 
> Usage:
> [root@localhost ~]# perf probe -x /bin/zsh zfree
> Add new event:
>   probe_zsh:zfree      (on /bin/zsh:0x45400)
> 
> You can now use it on all perf tools, such as:
> 
> 	perf record -e probe_zsh:zfree -aR sleep 1
> 
> [root@localhost ~]# perf record -e probe_zsh:zfree -aR sleep 15
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.314 MB perf.data (~13715 samples) ]
> [root@localhost ~]# perf report --stdio
> # Events: 3K probe_zsh:zfree
> #
> # Overhead  Command  Shared Object  Symbol
> # ........  .......  .............  ......
> #
>    100.00%              zsh  zsh            [.] zfree
> 
> 
> #
> # (For a higher level overview, try: perf report --sort comm,dso)
> #
> [root@localhost ~]
> 
> [ Probing a library function using function name ]
> --------------------------------------------------
> [root@localhost]#
> [root@localhost]# perf probe -x /lib64/libc.so.6 malloc
> Add new event:
>   probe_libc:malloc    (on /lib64/libc-2.5.so:0x74dc0)
> 
> You can now use it on all perf tools, such as:
> 
> 	perf record -e probe_libc:malloc -aR sleep 1
> 
> [root@localhost]#
> [root@localhost]# perf probe --list
>   probe_libc:malloc    (on /lib64/libc-2.5.so:0x0000000000074dc0)
> 
> 
> Show last 10 functions in /bin/zsh.
> 
> # perf probe -F -x /bin/zsh | tail
> zstrtol
> ztrcmp
> ztrdup
> ztrduppfx
> ztrftime
> ztrlen
> ztrncpy
> ztrsub
> zwarn
> zwarnnam
> 
> Show first 10 functions in /lib/libc.so.6
> 
> # perf probe -F -x /lib/libc.so.6 | head
> _IO_adjust_column
> _IO_adjust_wcolumn
> _IO_default_doallocate
> _IO_default_finish
> _IO_default_pbackfail
> _IO_default_uflow
> _IO_default_xsgetn
> _IO_default_xsputn
> _IO_do_write@@GLIBC_2.2.5
> _IO_doallocbuf
> 
>  tools/perf/Documentation/perf-probe.txt |   15 +
>  tools/perf/builtin-probe.c              |   42 +++
>  tools/perf/util/probe-event.c           |  424 +++++++++++++++++++++++++------
>  tools/perf/util/probe-event.h           |   12 +
>  tools/perf/util/symbol.c                |    8 +
>  tools/perf/util/symbol.h                |    1 
>  6 files changed, 405 insertions(+), 97 deletions(-)
> 
> diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
> index 2780d9c..fb673be 100644
> --- a/tools/perf/Documentation/perf-probe.txt
> +++ b/tools/perf/Documentation/perf-probe.txt
> @@ -77,7 +77,8 @@ OPTIONS
>  
>  -F::
>  --funcs::
> -	Show available functions in given module or kernel.
> +	Show available functions in given module or kernel. With -x/--exec,
> +	can also list functions in a user space executable / shared library.
>  
>  --filter=FILTER::
>  	(Only for --vars and --funcs) Set filter. FILTER is a combination of glob
> @@ -98,6 +99,11 @@ OPTIONS
>  --max-probes::
>  	Set the maximum number of probe points for an event. Default is 128.
>  
> +-x::
> +--exec=PATH::
> +	Specify path to the executable or shared library file for user
> +	space tracing. Can also be used with --funcs option.
> +
>  PROBE SYNTAX
>  ------------
>  Probe points are defined by following syntax.
> @@ -182,6 +188,13 @@ Delete all probes on schedule().
>  
>   ./perf probe --del='schedule*'
>  
> +Add probes at zfree() function on /bin/zsh
> +
> + ./perf probe -x /bin/zsh zfree
> +
> +Add probes at malloc() function on libc
> +
> + ./perf probe -x /lib/libc.so.6 malloc
>  
>  SEE ALSO
>  --------
> diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
> index 4935c09..c1bf0d8 100644
> --- a/tools/perf/builtin-probe.c
> +++ b/tools/perf/builtin-probe.c
> @@ -54,6 +54,7 @@ static struct {
>  	bool show_ext_vars;
>  	bool show_funcs;
>  	bool mod_events;
> +	bool uprobes;
>  	int nevents;
>  	struct perf_probe_event events[MAX_PROBES];
>  	struct strlist *dellist;
> @@ -75,6 +76,7 @@ static int parse_probe_event(const char *str)
>  		return -1;
>  	}
>  
> +	pev->uprobes = params.uprobes;
>  	/* Parse a perf-probe command into event */
>  	ret = parse_perf_probe_command(str, pev);
>  	pr_debug("%d arguments\n", pev->nargs);
> @@ -125,6 +127,28 @@ static int opt_del_probe_event(const struct option *opt __used,
>  	return 0;
>  }
>  
> +static int opt_set_target(const struct option *opt, const char *str,
> +			int unset __used)
> +{
> +	int ret = -ENOENT;
> +
> +	if  (str && !params.target) {
> +		if (!strcmp(opt->long_name, "exec"))
> +			params.uprobes = true;
> +#ifdef DWARF_SUPPORT
> +		else if (!strcmp(opt->long_name, "module"))
> +			params.uprobes = false;
> +#endif
> +		else
> +			return ret;
> +
> +		params.target = str;
> +		ret = 0;
> +	}
> +
> +	return ret;
> +}
> +
>  #ifdef DWARF_SUPPORT
>  static int opt_show_lines(const struct option *opt __used,
>  			  const char *str, int unset __used)
> @@ -246,9 +270,9 @@ static const struct option options[] = {
>  		   "file", "vmlinux pathname"),
>  	OPT_STRING('s', "source", &symbol_conf.source_prefix,
>  		   "directory", "path to kernel source"),
> -	OPT_STRING('m', "module", &params.target,
> -		   "modname|path",
> -		   "target module name (for online) or path (for offline)"),
> +	OPT_CALLBACK('m', "module", NULL, "modname|path",
> +		"target module name (for online) or path (for offline)",
> +		opt_set_target),
>  #endif
>  	OPT__DRY_RUN(&probe_event_dry_run),
>  	OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
> @@ -260,6 +284,8 @@ static const struct option options[] = {
>  		     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
>  		     "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
>  		     opt_set_filter),
> +	OPT_CALLBACK('x', "exec", NULL, "executable|path",
> +			"target executable name or path", opt_set_target),
>  	OPT_END()
>  };
>  
> @@ -310,6 +336,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
>  			pr_err("  Error: Don't use --list with --funcs.\n");
>  			usage_with_options(probe_usage, options);
>  		}
> +		if (params.uprobes) {
> +			pr_warning("  Error: Don't use --list with --exec.\n");
> +			usage_with_options(probe_usage, options);
> +		}
>  		ret = show_perf_probe_events();
>  		if (ret < 0)
>  			pr_err("  Error: Failed to show event list. (%d)\n",
> @@ -333,8 +363,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
>  		if (!params.filter)
>  			params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
>  						       NULL);
> -		ret = show_available_funcs(params.target,
> -					   params.filter);
> +		ret = show_available_funcs(params.target, params.filter,
> +					params.uprobes);
>  		strfilter__delete(params.filter);
>  		if (ret < 0)
>  			pr_err("  Error: Failed to show functions."
> @@ -343,7 +373,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
>  	}
>  
>  #ifdef DWARF_SUPPORT
> -	if (params.show_lines) {
> +	if (params.show_lines && !params.uprobes) {
>  		if (params.mod_events) {
>  			pr_err("  Error: Don't use --line with"
>  			       " --add/--del.\n");
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index 8a8ee64..b7dec82 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -44,6 +44,7 @@
>  #include "trace-event.h"	/* For __unused */
>  #include "probe-event.h"
>  #include "probe-finder.h"
> +#include "session.h"
>  
>  #define MAX_CMDLEN 256
>  #define MAX_PROBE_ARGS 128
> @@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
>  }
>  
>  static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
> +static int convert_name_to_addr(struct perf_probe_event *pev,
> +				const char *exec);
>  static struct machine machine;
>  
>  /* Initialize symbol maps and path of vmlinux/modules */
> @@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module)
>  	return (dso) ? dso->long_name : NULL;
>  }
>  
> +static int init_user_exec(void)
> +{
> +	int ret = 0;
> +
> +	symbol_conf.try_vmlinux_path = false;
> +	symbol_conf.sort_by_name = true;
> +	ret = symbol__init();
> +
> +	if (ret < 0)
> +		pr_debug("Failed to init symbol map.\n");
> +
> +	return ret;
> +}
> +
> +static int convert_to_perf_probe_point(struct probe_trace_point *tp,
> +					struct perf_probe_point *pp)
> +{
> +	pp->function = strdup(tp->symbol);
> +
> +	if (pp->function == NULL)
> +		return -ENOMEM;
> +
> +	pp->offset = tp->offset;
> +	pp->retprobe = tp->retprobe;
> +
> +	return 0;
> +}
> +
>  #ifdef DWARF_SUPPORT
>  /* Open new debuginfo of given module */
>  static struct debuginfo *open_debuginfo(const char *module)
> @@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
>  	if (ret <= 0) {
>  		pr_debug("Failed to find corresponding probes from "
>  			 "debuginfo. Use kprobe event information.\n");
> -		pp->function = strdup(tp->symbol);
> -		if (pp->function == NULL)
> -			return -ENOMEM;
> -		pp->offset = tp->offset;
> +		return convert_to_perf_probe_point(tp, pp);
>  	}
>  	pp->retprobe = tp->retprobe;
>  
> @@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
>  					  int max_tevs, const char *target)
>  {
>  	bool need_dwarf = perf_probe_event_need_dwarf(pev);
> -	struct debuginfo *dinfo = open_debuginfo(target);
> +	struct debuginfo *dinfo;
>  	int ntevs, ret = 0;
>  
> +	if (pev->uprobes) {
> +		if (need_dwarf) {
> +			pr_warning("Debuginfo-analysis is not yet supported"
> +					" with -x/--exec option.\n");
> +			return -ENOSYS;
> +		}
> +		return convert_name_to_addr(pev, target);
> +	}
> +
> +	dinfo = open_debuginfo(target);
> +
>  	if (!dinfo) {
>  		if (need_dwarf) {
>  			pr_warning("Failed to open debuginfo file.\n");
> @@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
>  		pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
>  		return -ENOENT;
>  	}
> -	pp->function = strdup(tp->symbol);
> -	if (pp->function == NULL)
> -		return -ENOMEM;
> -	pp->offset = tp->offset;
> -	pp->retprobe = tp->retprobe;
>  
> -	return 0;
> +	return convert_to_perf_probe_point(tp, pp);
>  }
>  
>  static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
>  				struct probe_trace_event **tevs __unused,
> -				int max_tevs __unused, const char *mod __unused)
> +				int max_tevs __unused, const char *target)
>  {
>  	if (perf_probe_event_need_dwarf(pev)) {
>  		pr_warning("Debuginfo-analysis is not supported.\n");
>  		return -ENOSYS;
>  	}
> +
> +	if (pev->uprobes)
> +		return convert_name_to_addr(pev, target);
> +
>  	return 0;
>  }
>  
> @@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
>  	if (buf == NULL)
>  		return NULL;
>  
> -	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
> -			 tp->retprobe ? 'r' : 'p',
> -			 tev->group, tev->event,
> -			 tp->module ?: "", tp->module ? ":" : "",
> -			 tp->symbol, tp->offset);
> +	if (tev->uprobes)
> +		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
> +				 tp->retprobe ? 'r' : 'p',
> +				 tev->group, tev->event,
> +				 tp->module, tp->symbol);
> +	else
> +		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
> +				 tp->retprobe ? 'r' : 'p',
> +				 tev->group, tev->event,
> +				 tp->module ?: "", tp->module ? ":" : "",
> +				 tp->symbol, tp->offset);
> +
>  	if (len <= 0)
>  		goto error;
>  
> @@ -1364,7 +1409,7 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
>  }
>  
>  static int convert_to_perf_probe_event(struct probe_trace_event *tev,
> -				       struct perf_probe_event *pev)
> +			       struct perf_probe_event *pev, bool is_kprobe)
>  {
>  	char buf[64] = "";
>  	int i, ret;
> @@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
>  		return -ENOMEM;
>  
>  	/* Convert trace_point to probe_point */
> -	ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
> +	if (is_kprobe)
> +		ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
> +	else
> +		ret = convert_to_perf_probe_point(&tev->point, &pev->point);
> +
>  	if (ret < 0)
>  		return ret;
>  
> @@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
>  	memset(tev, 0, sizeof(*tev));
>  }
>  
> -static int open_kprobe_events(bool readwrite)
> +static void print_warn_msg(const char *file, bool is_kprobe)
> +{
> +
> +	if (errno == ENOENT) {
> +		const char *config;
> +
> +		if (!is_kprobe)
> +			config = "CONFIG_UPROBE_EVENTS";
> +		else
> +			config = "CONFIG_KPROBE_EVENTS";
> +
> +		pr_warning("%s file does not exist - please rebuild kernel"
> +				" with %s.\n", file, config);
> +	} else
> +		pr_warning("Failed to open %s file: %s\n", file,
> +				strerror(errno));
> +}
> +
> +static int open_probe_events(const char *trace_file, bool readwrite,
> +				bool is_kprobe)
>  {
>  	char buf[PATH_MAX];
>  	const char *__debugfs;
> @@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite)
>  		return -ENOENT;
>  	}
>  
> -	ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
> +	ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
>  	if (ret >= 0) {
>  		pr_debug("Opening %s write=%d\n", buf, readwrite);
>  		if (readwrite && !probe_event_dry_run)
>  			ret = open(buf, O_RDWR, O_APPEND);
>  		else
>  			ret = open(buf, O_RDONLY, 0);
> -	}
>  
> -	if (ret < 0) {
> -		if (errno == ENOENT)
> -			pr_warning("kprobe_events file does not exist - please"
> -				 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
> -		else
> -			pr_warning("Failed to open kprobe_events file: %s\n",
> -				   strerror(errno));
> +		if (ret < 0)
> +			print_warn_msg(buf, is_kprobe);
>  	}
>  	return ret;
>  }
>  
> -/* Get raw string list of current kprobe_events */
> +static int open_kprobe_events(bool readwrite)
> +{
> +	return open_probe_events("tracing/kprobe_events", readwrite, true);
> +}
> +
> +static int open_uprobe_events(bool readwrite)
> +{
> +	return open_probe_events("tracing/uprobe_events", readwrite, false);
> +}
> +
> +/* Get raw string list of current kprobe_events  or uprobe_events */
>  static struct strlist *get_probe_trace_command_rawlist(int fd)
>  {
>  	int ret, idx;
> @@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
>  	return ret;
>  }
>  
> -/* List up current perf-probe events */
> -int show_perf_probe_events(void)
> +static int __show_perf_probe_events(int fd, bool is_kprobe)
>  {
> -	int fd, ret;
> +	int ret = 0;
>  	struct probe_trace_event tev;
>  	struct perf_probe_event pev;
>  	struct strlist *rawlist;
>  	struct str_node *ent;
>  
> -	setup_pager();
> -	ret = init_vmlinux();
> -	if (ret < 0)
> -		return ret;
> -
>  	memset(&tev, 0, sizeof(tev));
>  	memset(&pev, 0, sizeof(pev));
>  
> -	fd = open_kprobe_events(false);
> -	if (fd < 0)
> -		return fd;
> -
>  	rawlist = get_probe_trace_command_rawlist(fd);
> -	close(fd);
>  	if (!rawlist)
>  		return -ENOENT;
>  
>  	strlist__for_each(ent, rawlist) {
>  		ret = parse_probe_trace_command(ent->s, &tev);
>  		if (ret >= 0) {
> -			ret = convert_to_perf_probe_event(&tev, &pev);
> +			ret = convert_to_perf_probe_event(&tev, &pev,
> +								is_kprobe);
>  			if (ret >= 0)
>  				ret = show_perf_probe_event(&pev);
>  		}
> @@ -1612,6 +1674,33 @@ int show_perf_probe_events(void)
>  	return ret;
>  }
>  
> +/* List up current perf-probe events */
> +int show_perf_probe_events(void)
> +{
> +	int fd, ret;
> +
> +	setup_pager();
> +	fd = open_kprobe_events(false);
> +
> +	if (fd < 0)
> +		return fd;
> +
> +	ret = init_vmlinux();
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = __show_perf_probe_events(fd, true);
> +	close(fd);
> +
> +	fd = open_uprobe_events(false);
> +	if (fd >= 0) {
> +		ret = __show_perf_probe_events(fd, false);
> +		close(fd);
> +	}
> +
> +	return ret;
> +}
> +
>  /* Get current perf-probe event names */
>  static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
>  {
> @@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
>  	const char *event, *group;
>  	struct strlist *namelist;
>  
> -	fd = open_kprobe_events(true);
> +	if (pev->uprobes)
> +		fd = open_uprobe_events(true);
> +	else
> +		fd = open_kprobe_events(true);
> +
>  	if (fd < 0)
>  		return fd;
>  	/* Get current event names */
> @@ -1829,6 +1922,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
>  	tev->point.offset = pev->point.offset;
>  	tev->point.retprobe = pev->point.retprobe;
>  	tev->nargs = pev->nargs;
> +	tev->uprobes = pev->uprobes;
>  	if (tev->nargs) {
>  		tev->args = zalloc(sizeof(struct probe_trace_arg)
>  				   * tev->nargs);
> @@ -1859,6 +1953,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
>  		}
>  	}
>  
> +	if (pev->uprobes)
> +		return 1;
> +
>  	/* Currently just checking function name from symbol map */
>  	sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
>  	if (!sym) {
> @@ -1894,12 +1991,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
>  	int i, j, ret;
>  	struct __event_package *pkgs;
>  
> +	ret = 0;
>  	pkgs = zalloc(sizeof(struct __event_package) * npevs);
> +
>  	if (pkgs == NULL)
>  		return -ENOMEM;
>  
> -	/* Init vmlinux path */
> -	ret = init_vmlinux();
> +	if (!pevs->uprobes)
> +		/* Init vmlinux path */
> +		ret = init_vmlinux();
> +	else
> +		ret = init_user_exec();
> +
>  	if (ret < 0) {
>  		free(pkgs);
>  		return ret;
> @@ -1971,23 +2074,15 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
>  	return ret;
>  }
>  
> -static int del_trace_probe_event(int fd, const char *group,
> -				  const char *event, struct strlist *namelist)
> +static int del_trace_probe_event(int fd, const char *buf,
> +						  struct strlist *namelist)
>  {
> -	char buf[128];
>  	struct str_node *ent, *n;
> -	int found = 0, ret = 0;
> -
> -	ret = e_snprintf(buf, 128, "%s:%s", group, event);
> -	if (ret < 0) {
> -		pr_err("Failed to copy event.\n");
> -		return ret;
> -	}
> +	int ret = -1;
>  
>  	if (strpbrk(buf, "*?")) { /* Glob-exp */
>  		strlist__for_each_safe(ent, n, namelist)
>  			if (strglobmatch(ent->s, buf)) {
> -				found++;
>  				ret = __del_trace_probe_event(fd, ent);
>  				if (ret < 0)
>  					break;
> @@ -1996,40 +2091,43 @@ static int del_trace_probe_event(int fd, const char *group,
>  	} else {
>  		ent = strlist__find(namelist, buf);
>  		if (ent) {
> -			found++;
>  			ret = __del_trace_probe_event(fd, ent);
>  			if (ret >= 0)
>  				strlist__remove(namelist, ent);
>  		}
>  	}
> -	if (found == 0 && ret >= 0)
> -		pr_info("Info: Event \"%s\" does not exist.\n", buf);
>  
>  	return ret;
>  }
>  
>  int del_perf_probe_events(struct strlist *dellist)
>  {
> -	int fd, ret = 0;
> +	int ret = -1, ufd = -1, kfd = -1;
> +	char buf[128];
>  	const char *group, *event;
>  	char *p, *str;
>  	struct str_node *ent;
> -	struct strlist *namelist;
> -
> -	fd = open_kprobe_events(true);
> -	if (fd < 0)
> -		return fd;
> +	struct strlist *namelist = NULL, *unamelist = NULL;
>  
>  	/* Get current event names */
> -	namelist = get_probe_trace_event_names(fd, true);
> -	if (namelist == NULL)
> -		return -EINVAL;
> +	kfd = open_kprobe_events(true);
> +	if (kfd < 0)
> +		return kfd;
> +
> +	namelist = get_probe_trace_event_names(kfd, true);
> +	ufd = open_uprobe_events(true);
> +
> +	if (ufd >= 0)
> +		unamelist = get_probe_trace_event_names(ufd, true);
> +
> +	if (namelist == NULL && unamelist == NULL)
> +		goto error;
>  
>  	strlist__for_each(ent, dellist) {
>  		str = strdup(ent->s);
>  		if (str == NULL) {
>  			ret = -ENOMEM;
> -			break;
> +			goto error;
>  		}
>  		pr_debug("Parsing: %s\n", str);
>  		p = strchr(str, ':');
> @@ -2041,17 +2139,46 @@ int del_perf_probe_events(struct strlist *dellist)
>  			group = "*";
>  			event = str;
>  		}
> +
> +		ret = e_snprintf(buf, 128, "%s:%s", group, event);
> +		if (ret < 0) {
> +			pr_err("Failed to copy event.");
> +			free(str);
> +			goto error;
> +		}
> +
>  		pr_debug("Group: %s, Event: %s\n", group, event);
> -		ret = del_trace_probe_event(fd, group, event, namelist);
> +
> +		if (namelist)
> +			ret = del_trace_probe_event(kfd, buf, namelist);
> +
> +		if (unamelist && ret != 0)
> +			ret = del_trace_probe_event(ufd, buf, unamelist);
> +
> +		if (ret != 0)
> +			pr_info("Info: Event \"%s\" does not exist.\n", buf);
> +
>  		free(str);
> -		if (ret < 0)
> -			break;
>  	}
> -	strlist__delete(namelist);
> -	close(fd);
> +
> +error:
> +	if (kfd >= 0) {
> +		if (namelist)
> +			strlist__delete(namelist);
> +
> +		close(kfd);
> +	}
> +
> +	if (ufd >= 0) {
> +		if (unamelist)
> +			strlist__delete(unamelist);
> +
> +		close(ufd);
> +	}
>  
>  	return ret;
>  }
> +
>  /* TODO: don't use a global variable for filter ... */
>  static struct strfilter *available_func_filter;
>  
> @@ -2068,30 +2195,157 @@ static int filter_available_functions(struct map *map __unused,
>  	return 1;
>  }
>  
> -int show_available_funcs(const char *target, struct strfilter *_filter)
> +static int __show_available_funcs(struct map *map)
> +{
> +	if (map__load(map, filter_available_functions)) {
> +		pr_err("Failed to load map.\n");
> +		return -EINVAL;
> +	}
> +	if (!dso__sorted_by_name(map->dso, map->type))
> +		dso__sort_by_name(map->dso, map->type);
> +
> +	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
> +	return 0;
> +}
> +
> +static int available_kernel_funcs(const char *module)
>  {
>  	struct map *map;
>  	int ret;
>  
> -	setup_pager();
> -
>  	ret = init_vmlinux();
>  	if (ret < 0)
>  		return ret;
>  
> -	map = kernel_get_module_map(target);
> +	map = kernel_get_module_map(module);
>  	if (!map) {
> -		pr_err("Failed to find %s map.\n", (target) ? : "kernel");
> +		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
>  		return -EINVAL;
>  	}
> +	return __show_available_funcs(map);
> +}
> +
> +static int available_user_funcs(const char *target)
> +{
> +	struct map *map;
> +	int ret;
> +
> +	ret = init_user_exec();
> +	if (ret < 0)
> +		return ret;
> +
> +	map = dso__new_map(target);
> +	ret = __show_available_funcs(map);
> +	dso__delete(map->dso);
> +	map__delete(map);
> +	return ret;
> +}
> +
> +int show_available_funcs(const char *target, struct strfilter *_filter,
> +					bool user)
> +{
> +	setup_pager();
>  	available_func_filter = _filter;
> +
> +	if (!user)
> +		return available_kernel_funcs(target);
> +
> +	return available_user_funcs(target);
> +}
> +
> +/*
> + * uprobe_events only accepts address:
> + * Convert function and any offset to address
> + */
> +static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
> +{
> +	struct perf_probe_point *pp = &pev->point;
> +	struct symbol *sym;
> +	struct map *map = NULL;
> +	char *function = NULL, *name = NULL;
> +	int ret = -EINVAL;
> +	unsigned long long vaddr = 0;
> +
> +	if (!pp->function) {
> +		pr_warning("No function specified for uprobes");
> +		goto out;
> +	}
> +
> +	if (perf_probe_event_need_dwarf(pev)) {
> +		pr_warning("No dwarf based probes for uprobes.");
> +		goto out;
> +	}
> +
> +	function = strdup(pp->function);
> +	if (!function) {
> +		pr_warning("Failed to allocate memory by strdup.\n");
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	name = realpath(exec, NULL);
> +	if (!name) {
> +		pr_warning("Cannot find realpath for %s.\n", exec);
> +		goto out;
> +	}
> +	map = dso__new_map(name);
> +	if (!map) {
> +		pr_warning("Cannot find appropriate DSO for %s.\n", exec);
> +		goto out;
> +	}
> +	available_func_filter = strfilter__new(function, NULL);
>  	if (map__load(map, filter_available_functions)) {
>  		pr_err("Failed to load map.\n");
>  		return -EINVAL;
>  	}
> -	if (!dso__sorted_by_name(map->dso, map->type))
> -		dso__sort_by_name(map->dso, map->type);
>  
> -	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
> -	return 0;
> +	sym = map__find_symbol_by_name(map, function, NULL);
> +	if (!sym) {
> +		pr_warning("Cannot find %s in DSO %s\n", function, exec);
> +		goto out;
> +	}
> +
> +	if (map->start > sym->start)
> +		vaddr = map->start;
> +	vaddr += sym->start + pp->offset + map->pgoff;
> +	pp->offset = 0;
> +
> +	if (!pev->event) {
> +		pev->event = function;
> +		function = NULL;
> +	}
> +	if (!pev->group) {
> +		char *ptr1, *ptr2;
> +
> +		pev->group = zalloc(sizeof(char *) * 64);
> +		ptr1 = strdup(basename(exec));
> +		if (ptr1) {
> +			ptr2 = strpbrk(ptr1, "-._");
> +			if (ptr2)
> +				*ptr2 = '\0';
> +			e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
> +					ptr1);
> +			free(ptr1);
> +		}
> +	}
> +	free(pp->function);
> +	pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
> +	if (!pp->function) {
> +		ret = -ENOMEM;
> +		pr_warning("Failed to allocate memory by zalloc.\n");
> +		goto out;
> +	}
> +	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
> +	ret = 0;
> +
> +out:
> +	if (map) {
> +		dso__delete(map->dso);
> +		map__delete(map);
> +	}
> +	if (function)
> +		free(function);
> +	if (name)
> +		free(name);
> +	return ret;
>  }
> diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
> index a7dee83..f9f3de8 100644
> --- a/tools/perf/util/probe-event.h
> +++ b/tools/perf/util/probe-event.h
> @@ -7,7 +7,7 @@
>  
>  extern bool probe_event_dry_run;
>  
> -/* kprobe-tracer tracing point */
> +/* kprobe-tracer and uprobe-tracer tracing point */
>  struct probe_trace_point {
>  	char		*symbol;	/* Base symbol */
>  	char		*module;	/* Module name */
> @@ -21,7 +21,7 @@ struct probe_trace_arg_ref {
>  	long				offset;	/* Offset value */
>  };
>  
> -/* kprobe-tracer tracing argument */
> +/* kprobe-tracer and uprobe-tracer tracing argument */
>  struct probe_trace_arg {
>  	char				*name;	/* Argument name */
>  	char				*value;	/* Base value */
> @@ -29,12 +29,13 @@ struct probe_trace_arg {
>  	struct probe_trace_arg_ref	*ref;	/* Referencing offset */
>  };
>  
> -/* kprobe-tracer tracing event (point + arg) */
> +/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */
>  struct probe_trace_event {
>  	char				*event;	/* Event name */
>  	char				*group;	/* Group name */
>  	struct probe_trace_point	point;	/* Trace point */
>  	int				nargs;	/* Number of args */
> +	bool				uprobes;	/* uprobes only */
>  	struct probe_trace_arg		*args;	/* Arguments */
>  };
>  
> @@ -70,6 +71,7 @@ struct perf_probe_event {
>  	char			*group;	/* Group name */
>  	struct perf_probe_point	point;	/* Probe point */
>  	int			nargs;	/* Number of arguments */
> +	bool			uprobes;
>  	struct perf_probe_arg	*args;	/* Arguments */
>  };
>  
> @@ -129,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module);
>  extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
>  			       int max_probe_points, const char *module,
>  			       struct strfilter *filter, bool externs);
> -extern int show_available_funcs(const char *module, struct strfilter *filter);
> -
> +extern int show_available_funcs(const char *module, struct strfilter *filter,
> +				bool user);
>  
>  /* Maximum index number of event-name postfix */
>  #define MAX_EVENT_INDEX	1024
> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> index c0a028c..caaf75a 100644
> --- a/tools/perf/util/symbol.c
> +++ b/tools/perf/util/symbol.c
> @@ -2784,3 +2784,11 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
>  
>  	return ret;
>  }
> +
> +struct map *dso__new_map(const char *name)
> +{
> +	struct dso *dso = dso__new(name);
> +	struct map *map = map__new2(0, dso, MAP__FUNCTION);
> +
> +	return map;
> +}
> diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
> index ac49ef2..9e7742c 100644
> --- a/tools/perf/util/symbol.h
> +++ b/tools/perf/util/symbol.h
> @@ -237,6 +237,7 @@ void dso__set_long_name(struct dso *dso, char *name);
>  void dso__set_build_id(struct dso *dso, void *build_id);
>  void dso__read_running_kernel_build_id(struct dso *dso,
>  				       struct machine *machine);
> +struct map *dso__new_map(const char *name);
>  struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
>  				u64 addr);
>  struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
> 

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-11 14:49   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-04-11 14:49 UTC (permalink / raw)
  To: Srikar Dronamraju
  Cc: Peter Zijlstra, Ingo Molnar, Andrew Morton, Linus Torvalds,
	Ananth N Mavinakayanahalli, Jim Keniston, LKML, Linux-mm,
	Oleg Nesterov, Andi Kleen, Christoph Hellwig, Steven Rostedt,
	Masami Hiramatsu, Thomas Gleixner, Anton Arapov

Em Wed, Apr 11, 2012 at 07:27:42PM +0530, Srikar Dronamraju escreveu:
> From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
> 
> - Enhances perf to probe user space executables and libraries.
> - Enhances -F/--funcs option of "perf probe" to list possible probe points in
>   an executable file or library.
> - Documents userspace probing support in perf.
> 
> [ Probing a function in the executable using function name  ]
> perf probe -x /bin/zsh zfree
> 
> [ Probing a library function using function name ]
> perf probe -x /lib64/libc.so.6 malloc
> 
> [ list probe-able functions in an executable ]
> perf probe -F -x /bin/zsh
> 
> [ list probe-able functions in an library]
> perf probe -F -x /lib/libc.so.6

Can we avoid the need for -x? I.e. we could figure out it is userspace
and act accordingly.

- Arnaldo
 
> Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
> ---
> 
> Changelog:
> (v9)
> - Handled comments from Masami Hiramatsu that helps reduce code changes.
> - Handled usability comment(print complete name of file) from Ingo Molnar.
> 
> (v5)
> - Removed the separate documentation change patch and added the
>   documentation changes as part of this patch.
> 
> Usage:
> [root@localhost ~]# perf probe -x /bin/zsh zfree
> Add new event:
>   probe_zsh:zfree      (on /bin/zsh:0x45400)
> 
> You can now use it on all perf tools, such as:
> 
> 	perf record -e probe_zsh:zfree -aR sleep 1
> 
> [root@localhost ~]# perf record -e probe_zsh:zfree -aR sleep 15
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.314 MB perf.data (~13715 samples) ]
> [root@localhost ~]# perf report --stdio
> # Events: 3K probe_zsh:zfree
> #
> # Overhead  Command  Shared Object  Symbol
> # ........  .......  .............  ......
> #
>    100.00%              zsh  zsh            [.] zfree
> 
> 
> #
> # (For a higher level overview, try: perf report --sort comm,dso)
> #
> [root@localhost ~]
> 
> [ Probing a library function using function name ]
> --------------------------------------------------
> [root@localhost]#
> [root@localhost]# perf probe -x /lib64/libc.so.6 malloc
> Add new event:
>   probe_libc:malloc    (on /lib64/libc-2.5.so:0x74dc0)
> 
> You can now use it on all perf tools, such as:
> 
> 	perf record -e probe_libc:malloc -aR sleep 1
> 
> [root@localhost]#
> [root@localhost]# perf probe --list
>   probe_libc:malloc    (on /lib64/libc-2.5.so:0x0000000000074dc0)
> 
> 
> Show last 10 functions in /bin/zsh.
> 
> # perf probe -F -x /bin/zsh | tail
> zstrtol
> ztrcmp
> ztrdup
> ztrduppfx
> ztrftime
> ztrlen
> ztrncpy
> ztrsub
> zwarn
> zwarnnam
> 
> Show first 10 functions in /lib/libc.so.6
> 
> # perf probe -F -x /lib/libc.so.6 | head
> _IO_adjust_column
> _IO_adjust_wcolumn
> _IO_default_doallocate
> _IO_default_finish
> _IO_default_pbackfail
> _IO_default_uflow
> _IO_default_xsgetn
> _IO_default_xsputn
> _IO_do_write@@GLIBC_2.2.5
> _IO_doallocbuf
> 
>  tools/perf/Documentation/perf-probe.txt |   15 +
>  tools/perf/builtin-probe.c              |   42 +++
>  tools/perf/util/probe-event.c           |  424 +++++++++++++++++++++++++------
>  tools/perf/util/probe-event.h           |   12 +
>  tools/perf/util/symbol.c                |    8 +
>  tools/perf/util/symbol.h                |    1 
>  6 files changed, 405 insertions(+), 97 deletions(-)
> 
> diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
> index 2780d9c..fb673be 100644
> --- a/tools/perf/Documentation/perf-probe.txt
> +++ b/tools/perf/Documentation/perf-probe.txt
> @@ -77,7 +77,8 @@ OPTIONS
>  
>  -F::
>  --funcs::
> -	Show available functions in given module or kernel.
> +	Show available functions in given module or kernel. With -x/--exec,
> +	can also list functions in a user space executable / shared library.
>  
>  --filter=FILTER::
>  	(Only for --vars and --funcs) Set filter. FILTER is a combination of glob
> @@ -98,6 +99,11 @@ OPTIONS
>  --max-probes::
>  	Set the maximum number of probe points for an event. Default is 128.
>  
> +-x::
> +--exec=PATH::
> +	Specify path to the executable or shared library file for user
> +	space tracing. Can also be used with --funcs option.
> +
>  PROBE SYNTAX
>  ------------
>  Probe points are defined by following syntax.
> @@ -182,6 +188,13 @@ Delete all probes on schedule().
>  
>   ./perf probe --del='schedule*'
>  
> +Add probes at zfree() function on /bin/zsh
> +
> + ./perf probe -x /bin/zsh zfree
> +
> +Add probes at malloc() function on libc
> +
> + ./perf probe -x /lib/libc.so.6 malloc
>  
>  SEE ALSO
>  --------
> diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
> index 4935c09..c1bf0d8 100644
> --- a/tools/perf/builtin-probe.c
> +++ b/tools/perf/builtin-probe.c
> @@ -54,6 +54,7 @@ static struct {
>  	bool show_ext_vars;
>  	bool show_funcs;
>  	bool mod_events;
> +	bool uprobes;
>  	int nevents;
>  	struct perf_probe_event events[MAX_PROBES];
>  	struct strlist *dellist;
> @@ -75,6 +76,7 @@ static int parse_probe_event(const char *str)
>  		return -1;
>  	}
>  
> +	pev->uprobes = params.uprobes;
>  	/* Parse a perf-probe command into event */
>  	ret = parse_perf_probe_command(str, pev);
>  	pr_debug("%d arguments\n", pev->nargs);
> @@ -125,6 +127,28 @@ static int opt_del_probe_event(const struct option *opt __used,
>  	return 0;
>  }
>  
> +static int opt_set_target(const struct option *opt, const char *str,
> +			int unset __used)
> +{
> +	int ret = -ENOENT;
> +
> +	if  (str && !params.target) {
> +		if (!strcmp(opt->long_name, "exec"))
> +			params.uprobes = true;
> +#ifdef DWARF_SUPPORT
> +		else if (!strcmp(opt->long_name, "module"))
> +			params.uprobes = false;
> +#endif
> +		else
> +			return ret;
> +
> +		params.target = str;
> +		ret = 0;
> +	}
> +
> +	return ret;
> +}
> +
>  #ifdef DWARF_SUPPORT
>  static int opt_show_lines(const struct option *opt __used,
>  			  const char *str, int unset __used)
> @@ -246,9 +270,9 @@ static const struct option options[] = {
>  		   "file", "vmlinux pathname"),
>  	OPT_STRING('s', "source", &symbol_conf.source_prefix,
>  		   "directory", "path to kernel source"),
> -	OPT_STRING('m', "module", &params.target,
> -		   "modname|path",
> -		   "target module name (for online) or path (for offline)"),
> +	OPT_CALLBACK('m', "module", NULL, "modname|path",
> +		"target module name (for online) or path (for offline)",
> +		opt_set_target),
>  #endif
>  	OPT__DRY_RUN(&probe_event_dry_run),
>  	OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
> @@ -260,6 +284,8 @@ static const struct option options[] = {
>  		     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
>  		     "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
>  		     opt_set_filter),
> +	OPT_CALLBACK('x', "exec", NULL, "executable|path",
> +			"target executable name or path", opt_set_target),
>  	OPT_END()
>  };
>  
> @@ -310,6 +336,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
>  			pr_err("  Error: Don't use --list with --funcs.\n");
>  			usage_with_options(probe_usage, options);
>  		}
> +		if (params.uprobes) {
> +			pr_warning("  Error: Don't use --list with --exec.\n");
> +			usage_with_options(probe_usage, options);
> +		}
>  		ret = show_perf_probe_events();
>  		if (ret < 0)
>  			pr_err("  Error: Failed to show event list. (%d)\n",
> @@ -333,8 +363,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
>  		if (!params.filter)
>  			params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
>  						       NULL);
> -		ret = show_available_funcs(params.target,
> -					   params.filter);
> +		ret = show_available_funcs(params.target, params.filter,
> +					params.uprobes);
>  		strfilter__delete(params.filter);
>  		if (ret < 0)
>  			pr_err("  Error: Failed to show functions."
> @@ -343,7 +373,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
>  	}
>  
>  #ifdef DWARF_SUPPORT
> -	if (params.show_lines) {
> +	if (params.show_lines && !params.uprobes) {
>  		if (params.mod_events) {
>  			pr_err("  Error: Don't use --line with"
>  			       " --add/--del.\n");
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index 8a8ee64..b7dec82 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -44,6 +44,7 @@
>  #include "trace-event.h"	/* For __unused */
>  #include "probe-event.h"
>  #include "probe-finder.h"
> +#include "session.h"
>  
>  #define MAX_CMDLEN 256
>  #define MAX_PROBE_ARGS 128
> @@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
>  }
>  
>  static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
> +static int convert_name_to_addr(struct perf_probe_event *pev,
> +				const char *exec);
>  static struct machine machine;
>  
>  /* Initialize symbol maps and path of vmlinux/modules */
> @@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module)
>  	return (dso) ? dso->long_name : NULL;
>  }
>  
> +static int init_user_exec(void)
> +{
> +	int ret = 0;
> +
> +	symbol_conf.try_vmlinux_path = false;
> +	symbol_conf.sort_by_name = true;
> +	ret = symbol__init();
> +
> +	if (ret < 0)
> +		pr_debug("Failed to init symbol map.\n");
> +
> +	return ret;
> +}
> +
> +static int convert_to_perf_probe_point(struct probe_trace_point *tp,
> +					struct perf_probe_point *pp)
> +{
> +	pp->function = strdup(tp->symbol);
> +
> +	if (pp->function == NULL)
> +		return -ENOMEM;
> +
> +	pp->offset = tp->offset;
> +	pp->retprobe = tp->retprobe;
> +
> +	return 0;
> +}
> +
>  #ifdef DWARF_SUPPORT
>  /* Open new debuginfo of given module */
>  static struct debuginfo *open_debuginfo(const char *module)
> @@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
>  	if (ret <= 0) {
>  		pr_debug("Failed to find corresponding probes from "
>  			 "debuginfo. Use kprobe event information.\n");
> -		pp->function = strdup(tp->symbol);
> -		if (pp->function == NULL)
> -			return -ENOMEM;
> -		pp->offset = tp->offset;
> +		return convert_to_perf_probe_point(tp, pp);
>  	}
>  	pp->retprobe = tp->retprobe;
>  
> @@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
>  					  int max_tevs, const char *target)
>  {
>  	bool need_dwarf = perf_probe_event_need_dwarf(pev);
> -	struct debuginfo *dinfo = open_debuginfo(target);
> +	struct debuginfo *dinfo;
>  	int ntevs, ret = 0;
>  
> +	if (pev->uprobes) {
> +		if (need_dwarf) {
> +			pr_warning("Debuginfo-analysis is not yet supported"
> +					" with -x/--exec option.\n");
> +			return -ENOSYS;
> +		}
> +		return convert_name_to_addr(pev, target);
> +	}
> +
> +	dinfo = open_debuginfo(target);
> +
>  	if (!dinfo) {
>  		if (need_dwarf) {
>  			pr_warning("Failed to open debuginfo file.\n");
> @@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
>  		pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
>  		return -ENOENT;
>  	}
> -	pp->function = strdup(tp->symbol);
> -	if (pp->function == NULL)
> -		return -ENOMEM;
> -	pp->offset = tp->offset;
> -	pp->retprobe = tp->retprobe;
>  
> -	return 0;
> +	return convert_to_perf_probe_point(tp, pp);
>  }
>  
>  static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
>  				struct probe_trace_event **tevs __unused,
> -				int max_tevs __unused, const char *mod __unused)
> +				int max_tevs __unused, const char *target)
>  {
>  	if (perf_probe_event_need_dwarf(pev)) {
>  		pr_warning("Debuginfo-analysis is not supported.\n");
>  		return -ENOSYS;
>  	}
> +
> +	if (pev->uprobes)
> +		return convert_name_to_addr(pev, target);
> +
>  	return 0;
>  }
>  
> @@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
>  	if (buf == NULL)
>  		return NULL;
>  
> -	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
> -			 tp->retprobe ? 'r' : 'p',
> -			 tev->group, tev->event,
> -			 tp->module ?: "", tp->module ? ":" : "",
> -			 tp->symbol, tp->offset);
> +	if (tev->uprobes)
> +		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
> +				 tp->retprobe ? 'r' : 'p',
> +				 tev->group, tev->event,
> +				 tp->module, tp->symbol);
> +	else
> +		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
> +				 tp->retprobe ? 'r' : 'p',
> +				 tev->group, tev->event,
> +				 tp->module ?: "", tp->module ? ":" : "",
> +				 tp->symbol, tp->offset);
> +
>  	if (len <= 0)
>  		goto error;
>  
> @@ -1364,7 +1409,7 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
>  }
>  
>  static int convert_to_perf_probe_event(struct probe_trace_event *tev,
> -				       struct perf_probe_event *pev)
> +			       struct perf_probe_event *pev, bool is_kprobe)
>  {
>  	char buf[64] = "";
>  	int i, ret;
> @@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
>  		return -ENOMEM;
>  
>  	/* Convert trace_point to probe_point */
> -	ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
> +	if (is_kprobe)
> +		ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
> +	else
> +		ret = convert_to_perf_probe_point(&tev->point, &pev->point);
> +
>  	if (ret < 0)
>  		return ret;
>  
> @@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
>  	memset(tev, 0, sizeof(*tev));
>  }
>  
> -static int open_kprobe_events(bool readwrite)
> +static void print_warn_msg(const char *file, bool is_kprobe)
> +{
> +
> +	if (errno == ENOENT) {
> +		const char *config;
> +
> +		if (!is_kprobe)
> +			config = "CONFIG_UPROBE_EVENTS";
> +		else
> +			config = "CONFIG_KPROBE_EVENTS";
> +
> +		pr_warning("%s file does not exist - please rebuild kernel"
> +				" with %s.\n", file, config);
> +	} else
> +		pr_warning("Failed to open %s file: %s\n", file,
> +				strerror(errno));
> +}
> +
> +static int open_probe_events(const char *trace_file, bool readwrite,
> +				bool is_kprobe)
>  {
>  	char buf[PATH_MAX];
>  	const char *__debugfs;
> @@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite)
>  		return -ENOENT;
>  	}
>  
> -	ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
> +	ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
>  	if (ret >= 0) {
>  		pr_debug("Opening %s write=%d\n", buf, readwrite);
>  		if (readwrite && !probe_event_dry_run)
>  			ret = open(buf, O_RDWR, O_APPEND);
>  		else
>  			ret = open(buf, O_RDONLY, 0);
> -	}
>  
> -	if (ret < 0) {
> -		if (errno == ENOENT)
> -			pr_warning("kprobe_events file does not exist - please"
> -				 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
> -		else
> -			pr_warning("Failed to open kprobe_events file: %s\n",
> -				   strerror(errno));
> +		if (ret < 0)
> +			print_warn_msg(buf, is_kprobe);
>  	}
>  	return ret;
>  }
>  
> -/* Get raw string list of current kprobe_events */
> +static int open_kprobe_events(bool readwrite)
> +{
> +	return open_probe_events("tracing/kprobe_events", readwrite, true);
> +}
> +
> +static int open_uprobe_events(bool readwrite)
> +{
> +	return open_probe_events("tracing/uprobe_events", readwrite, false);
> +}
> +
> +/* Get raw string list of current kprobe_events  or uprobe_events */
>  static struct strlist *get_probe_trace_command_rawlist(int fd)
>  {
>  	int ret, idx;
> @@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
>  	return ret;
>  }
>  
> -/* List up current perf-probe events */
> -int show_perf_probe_events(void)
> +static int __show_perf_probe_events(int fd, bool is_kprobe)
>  {
> -	int fd, ret;
> +	int ret = 0;
>  	struct probe_trace_event tev;
>  	struct perf_probe_event pev;
>  	struct strlist *rawlist;
>  	struct str_node *ent;
>  
> -	setup_pager();
> -	ret = init_vmlinux();
> -	if (ret < 0)
> -		return ret;
> -
>  	memset(&tev, 0, sizeof(tev));
>  	memset(&pev, 0, sizeof(pev));
>  
> -	fd = open_kprobe_events(false);
> -	if (fd < 0)
> -		return fd;
> -
>  	rawlist = get_probe_trace_command_rawlist(fd);
> -	close(fd);
>  	if (!rawlist)
>  		return -ENOENT;
>  
>  	strlist__for_each(ent, rawlist) {
>  		ret = parse_probe_trace_command(ent->s, &tev);
>  		if (ret >= 0) {
> -			ret = convert_to_perf_probe_event(&tev, &pev);
> +			ret = convert_to_perf_probe_event(&tev, &pev,
> +								is_kprobe);
>  			if (ret >= 0)
>  				ret = show_perf_probe_event(&pev);
>  		}
> @@ -1612,6 +1674,33 @@ int show_perf_probe_events(void)
>  	return ret;
>  }
>  
> +/* List up current perf-probe events */
> +int show_perf_probe_events(void)
> +{
> +	int fd, ret;
> +
> +	setup_pager();
> +	fd = open_kprobe_events(false);
> +
> +	if (fd < 0)
> +		return fd;
> +
> +	ret = init_vmlinux();
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = __show_perf_probe_events(fd, true);
> +	close(fd);
> +
> +	fd = open_uprobe_events(false);
> +	if (fd >= 0) {
> +		ret = __show_perf_probe_events(fd, false);
> +		close(fd);
> +	}
> +
> +	return ret;
> +}
> +
>  /* Get current perf-probe event names */
>  static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
>  {
> @@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
>  	const char *event, *group;
>  	struct strlist *namelist;
>  
> -	fd = open_kprobe_events(true);
> +	if (pev->uprobes)
> +		fd = open_uprobe_events(true);
> +	else
> +		fd = open_kprobe_events(true);
> +
>  	if (fd < 0)
>  		return fd;
>  	/* Get current event names */
> @@ -1829,6 +1922,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
>  	tev->point.offset = pev->point.offset;
>  	tev->point.retprobe = pev->point.retprobe;
>  	tev->nargs = pev->nargs;
> +	tev->uprobes = pev->uprobes;
>  	if (tev->nargs) {
>  		tev->args = zalloc(sizeof(struct probe_trace_arg)
>  				   * tev->nargs);
> @@ -1859,6 +1953,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
>  		}
>  	}
>  
> +	if (pev->uprobes)
> +		return 1;
> +
>  	/* Currently just checking function name from symbol map */
>  	sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
>  	if (!sym) {
> @@ -1894,12 +1991,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
>  	int i, j, ret;
>  	struct __event_package *pkgs;
>  
> +	ret = 0;
>  	pkgs = zalloc(sizeof(struct __event_package) * npevs);
> +
>  	if (pkgs == NULL)
>  		return -ENOMEM;
>  
> -	/* Init vmlinux path */
> -	ret = init_vmlinux();
> +	if (!pevs->uprobes)
> +		/* Init vmlinux path */
> +		ret = init_vmlinux();
> +	else
> +		ret = init_user_exec();
> +
>  	if (ret < 0) {
>  		free(pkgs);
>  		return ret;
> @@ -1971,23 +2074,15 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
>  	return ret;
>  }
>  
> -static int del_trace_probe_event(int fd, const char *group,
> -				  const char *event, struct strlist *namelist)
> +static int del_trace_probe_event(int fd, const char *buf,
> +						  struct strlist *namelist)
>  {
> -	char buf[128];
>  	struct str_node *ent, *n;
> -	int found = 0, ret = 0;
> -
> -	ret = e_snprintf(buf, 128, "%s:%s", group, event);
> -	if (ret < 0) {
> -		pr_err("Failed to copy event.\n");
> -		return ret;
> -	}
> +	int ret = -1;
>  
>  	if (strpbrk(buf, "*?")) { /* Glob-exp */
>  		strlist__for_each_safe(ent, n, namelist)
>  			if (strglobmatch(ent->s, buf)) {
> -				found++;
>  				ret = __del_trace_probe_event(fd, ent);
>  				if (ret < 0)
>  					break;
> @@ -1996,40 +2091,43 @@ static int del_trace_probe_event(int fd, const char *group,
>  	} else {
>  		ent = strlist__find(namelist, buf);
>  		if (ent) {
> -			found++;
>  			ret = __del_trace_probe_event(fd, ent);
>  			if (ret >= 0)
>  				strlist__remove(namelist, ent);
>  		}
>  	}
> -	if (found == 0 && ret >= 0)
> -		pr_info("Info: Event \"%s\" does not exist.\n", buf);
>  
>  	return ret;
>  }
>  
>  int del_perf_probe_events(struct strlist *dellist)
>  {
> -	int fd, ret = 0;
> +	int ret = -1, ufd = -1, kfd = -1;
> +	char buf[128];
>  	const char *group, *event;
>  	char *p, *str;
>  	struct str_node *ent;
> -	struct strlist *namelist;
> -
> -	fd = open_kprobe_events(true);
> -	if (fd < 0)
> -		return fd;
> +	struct strlist *namelist = NULL, *unamelist = NULL;
>  
>  	/* Get current event names */
> -	namelist = get_probe_trace_event_names(fd, true);
> -	if (namelist == NULL)
> -		return -EINVAL;
> +	kfd = open_kprobe_events(true);
> +	if (kfd < 0)
> +		return kfd;
> +
> +	namelist = get_probe_trace_event_names(kfd, true);
> +	ufd = open_uprobe_events(true);
> +
> +	if (ufd >= 0)
> +		unamelist = get_probe_trace_event_names(ufd, true);
> +
> +	if (namelist == NULL && unamelist == NULL)
> +		goto error;
>  
>  	strlist__for_each(ent, dellist) {
>  		str = strdup(ent->s);
>  		if (str == NULL) {
>  			ret = -ENOMEM;
> -			break;
> +			goto error;
>  		}
>  		pr_debug("Parsing: %s\n", str);
>  		p = strchr(str, ':');
> @@ -2041,17 +2139,46 @@ int del_perf_probe_events(struct strlist *dellist)
>  			group = "*";
>  			event = str;
>  		}
> +
> +		ret = e_snprintf(buf, 128, "%s:%s", group, event);
> +		if (ret < 0) {
> +			pr_err("Failed to copy event.");
> +			free(str);
> +			goto error;
> +		}
> +
>  		pr_debug("Group: %s, Event: %s\n", group, event);
> -		ret = del_trace_probe_event(fd, group, event, namelist);
> +
> +		if (namelist)
> +			ret = del_trace_probe_event(kfd, buf, namelist);
> +
> +		if (unamelist && ret != 0)
> +			ret = del_trace_probe_event(ufd, buf, unamelist);
> +
> +		if (ret != 0)
> +			pr_info("Info: Event \"%s\" does not exist.\n", buf);
> +
>  		free(str);
> -		if (ret < 0)
> -			break;
>  	}
> -	strlist__delete(namelist);
> -	close(fd);
> +
> +error:
> +	if (kfd >= 0) {
> +		if (namelist)
> +			strlist__delete(namelist);
> +
> +		close(kfd);
> +	}
> +
> +	if (ufd >= 0) {
> +		if (unamelist)
> +			strlist__delete(unamelist);
> +
> +		close(ufd);
> +	}
>  
>  	return ret;
>  }
> +
>  /* TODO: don't use a global variable for filter ... */
>  static struct strfilter *available_func_filter;
>  
> @@ -2068,30 +2195,157 @@ static int filter_available_functions(struct map *map __unused,
>  	return 1;
>  }
>  
> -int show_available_funcs(const char *target, struct strfilter *_filter)
> +static int __show_available_funcs(struct map *map)
> +{
> +	if (map__load(map, filter_available_functions)) {
> +		pr_err("Failed to load map.\n");
> +		return -EINVAL;
> +	}
> +	if (!dso__sorted_by_name(map->dso, map->type))
> +		dso__sort_by_name(map->dso, map->type);
> +
> +	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
> +	return 0;
> +}
> +
> +static int available_kernel_funcs(const char *module)
>  {
>  	struct map *map;
>  	int ret;
>  
> -	setup_pager();
> -
>  	ret = init_vmlinux();
>  	if (ret < 0)
>  		return ret;
>  
> -	map = kernel_get_module_map(target);
> +	map = kernel_get_module_map(module);
>  	if (!map) {
> -		pr_err("Failed to find %s map.\n", (target) ? : "kernel");
> +		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
>  		return -EINVAL;
>  	}
> +	return __show_available_funcs(map);
> +}
> +
> +static int available_user_funcs(const char *target)
> +{
> +	struct map *map;
> +	int ret;
> +
> +	ret = init_user_exec();
> +	if (ret < 0)
> +		return ret;
> +
> +	map = dso__new_map(target);
> +	ret = __show_available_funcs(map);
> +	dso__delete(map->dso);
> +	map__delete(map);
> +	return ret;
> +}
> +
> +int show_available_funcs(const char *target, struct strfilter *_filter,
> +					bool user)
> +{
> +	setup_pager();
>  	available_func_filter = _filter;
> +
> +	if (!user)
> +		return available_kernel_funcs(target);
> +
> +	return available_user_funcs(target);
> +}
> +
> +/*
> + * uprobe_events only accepts address:
> + * Convert function and any offset to address
> + */
> +static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
> +{
> +	struct perf_probe_point *pp = &pev->point;
> +	struct symbol *sym;
> +	struct map *map = NULL;
> +	char *function = NULL, *name = NULL;
> +	int ret = -EINVAL;
> +	unsigned long long vaddr = 0;
> +
> +	if (!pp->function) {
> +		pr_warning("No function specified for uprobes");
> +		goto out;
> +	}
> +
> +	if (perf_probe_event_need_dwarf(pev)) {
> +		pr_warning("No dwarf based probes for uprobes.");
> +		goto out;
> +	}
> +
> +	function = strdup(pp->function);
> +	if (!function) {
> +		pr_warning("Failed to allocate memory by strdup.\n");
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	name = realpath(exec, NULL);
> +	if (!name) {
> +		pr_warning("Cannot find realpath for %s.\n", exec);
> +		goto out;
> +	}
> +	map = dso__new_map(name);
> +	if (!map) {
> +		pr_warning("Cannot find appropriate DSO for %s.\n", exec);
> +		goto out;
> +	}
> +	available_func_filter = strfilter__new(function, NULL);
>  	if (map__load(map, filter_available_functions)) {
>  		pr_err("Failed to load map.\n");
>  		return -EINVAL;
>  	}
> -	if (!dso__sorted_by_name(map->dso, map->type))
> -		dso__sort_by_name(map->dso, map->type);
>  
> -	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
> -	return 0;
> +	sym = map__find_symbol_by_name(map, function, NULL);
> +	if (!sym) {
> +		pr_warning("Cannot find %s in DSO %s\n", function, exec);
> +		goto out;
> +	}
> +
> +	if (map->start > sym->start)
> +		vaddr = map->start;
> +	vaddr += sym->start + pp->offset + map->pgoff;
> +	pp->offset = 0;
> +
> +	if (!pev->event) {
> +		pev->event = function;
> +		function = NULL;
> +	}
> +	if (!pev->group) {
> +		char *ptr1, *ptr2;
> +
> +		pev->group = zalloc(sizeof(char *) * 64);
> +		ptr1 = strdup(basename(exec));
> +		if (ptr1) {
> +			ptr2 = strpbrk(ptr1, "-._");
> +			if (ptr2)
> +				*ptr2 = '\0';
> +			e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
> +					ptr1);
> +			free(ptr1);
> +		}
> +	}
> +	free(pp->function);
> +	pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
> +	if (!pp->function) {
> +		ret = -ENOMEM;
> +		pr_warning("Failed to allocate memory by zalloc.\n");
> +		goto out;
> +	}
> +	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
> +	ret = 0;
> +
> +out:
> +	if (map) {
> +		dso__delete(map->dso);
> +		map__delete(map);
> +	}
> +	if (function)
> +		free(function);
> +	if (name)
> +		free(name);
> +	return ret;
>  }
> diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
> index a7dee83..f9f3de8 100644
> --- a/tools/perf/util/probe-event.h
> +++ b/tools/perf/util/probe-event.h
> @@ -7,7 +7,7 @@
>  
>  extern bool probe_event_dry_run;
>  
> -/* kprobe-tracer tracing point */
> +/* kprobe-tracer and uprobe-tracer tracing point */
>  struct probe_trace_point {
>  	char		*symbol;	/* Base symbol */
>  	char		*module;	/* Module name */
> @@ -21,7 +21,7 @@ struct probe_trace_arg_ref {
>  	long				offset;	/* Offset value */
>  };
>  
> -/* kprobe-tracer tracing argument */
> +/* kprobe-tracer and uprobe-tracer tracing argument */
>  struct probe_trace_arg {
>  	char				*name;	/* Argument name */
>  	char				*value;	/* Base value */
> @@ -29,12 +29,13 @@ struct probe_trace_arg {
>  	struct probe_trace_arg_ref	*ref;	/* Referencing offset */
>  };
>  
> -/* kprobe-tracer tracing event (point + arg) */
> +/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */
>  struct probe_trace_event {
>  	char				*event;	/* Event name */
>  	char				*group;	/* Group name */
>  	struct probe_trace_point	point;	/* Trace point */
>  	int				nargs;	/* Number of args */
> +	bool				uprobes;	/* uprobes only */
>  	struct probe_trace_arg		*args;	/* Arguments */
>  };
>  
> @@ -70,6 +71,7 @@ struct perf_probe_event {
>  	char			*group;	/* Group name */
>  	struct perf_probe_point	point;	/* Probe point */
>  	int			nargs;	/* Number of arguments */
> +	bool			uprobes;
>  	struct perf_probe_arg	*args;	/* Arguments */
>  };
>  
> @@ -129,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module);
>  extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
>  			       int max_probe_points, const char *module,
>  			       struct strfilter *filter, bool externs);
> -extern int show_available_funcs(const char *module, struct strfilter *filter);
> -
> +extern int show_available_funcs(const char *module, struct strfilter *filter,
> +				bool user);
>  
>  /* Maximum index number of event-name postfix */
>  #define MAX_EVENT_INDEX	1024
> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> index c0a028c..caaf75a 100644
> --- a/tools/perf/util/symbol.c
> +++ b/tools/perf/util/symbol.c
> @@ -2784,3 +2784,11 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
>  
>  	return ret;
>  }
> +
> +struct map *dso__new_map(const char *name)
> +{
> +	struct dso *dso = dso__new(name);
> +	struct map *map = map__new2(0, dso, MAP__FUNCTION);
> +
> +	return map;
> +}
> diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
> index ac49ef2..9e7742c 100644
> --- a/tools/perf/util/symbol.h
> +++ b/tools/perf/util/symbol.h
> @@ -237,6 +237,7 @@ void dso__set_long_name(struct dso *dso, char *name);
>  void dso__set_build_id(struct dso *dso, void *build_id);
>  void dso__read_running_kernel_build_id(struct dso *dso,
>  				       struct machine *machine);
> +struct map *dso__new_map(const char *name);
>  struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
>  				u64 addr);
>  struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
> 

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] perf/probe: Provide perf interface for uprobes
  2012-04-11 14:49   ` Arnaldo Carvalho de Melo
@ 2012-04-11 17:12     ` Srikar Dronamraju
  -1 siblings, 0 replies; 24+ messages in thread
From: Srikar Dronamraju @ 2012-04-11 17:12 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Ingo Molnar, Andrew Morton, Linus Torvalds,
	Ananth N Mavinakayanahalli, Jim Keniston, LKML, Linux-mm,
	Oleg Nesterov, Andi Kleen, Christoph Hellwig, Steven Rostedt,
	Masami Hiramatsu, Thomas Gleixner, Anton Arapov

* Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-11 11:49:18]:

> Em Wed, Apr 11, 2012 at 07:27:42PM +0530, Srikar Dronamraju escreveu:
> > From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
> > 
> > - Enhances perf to probe user space executables and libraries.
> > - Enhances -F/--funcs option of "perf probe" to list possible probe points in
> >   an executable file or library.
> > - Documents userspace probing support in perf.
> > 
> > [ Probing a function in the executable using function name  ]
> > perf probe -x /bin/zsh zfree
> > 
> > [ Probing a library function using function name ]
> > perf probe -x /lib64/libc.so.6 malloc
> > 
> > [ list probe-able functions in an executable ]
> > perf probe -F -x /bin/zsh
> > 
> > [ list probe-able functions in an library]
> > perf probe -F -x /lib/libc.so.6
> 
> Can we avoid the need for -x? I.e. we could figure out it is userspace
> and act accordingly.
> 

To list the functions in the module ipv6, we use "perf probe -F -m ipv6"
So I used the same logic to use -x for specifying executables.


This is in agreement with probepoint addition where without any
additional options would mean kernel probepoint; m option would mean
module and x option would mean user space executable. 

However if you still think we should change, do let me know.

-- 
Thanks and Regards
Srikar


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-11 17:12     ` Srikar Dronamraju
  0 siblings, 0 replies; 24+ messages in thread
From: Srikar Dronamraju @ 2012-04-11 17:12 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, Ingo Molnar, Andrew Morton, Linus Torvalds,
	Ananth N Mavinakayanahalli, Jim Keniston, LKML, Linux-mm,
	Oleg Nesterov, Andi Kleen, Christoph Hellwig, Steven Rostedt,
	Masami Hiramatsu, Thomas Gleixner, Anton Arapov

* Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-11 11:49:18]:

> Em Wed, Apr 11, 2012 at 07:27:42PM +0530, Srikar Dronamraju escreveu:
> > From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
> > 
> > - Enhances perf to probe user space executables and libraries.
> > - Enhances -F/--funcs option of "perf probe" to list possible probe points in
> >   an executable file or library.
> > - Documents userspace probing support in perf.
> > 
> > [ Probing a function in the executable using function name  ]
> > perf probe -x /bin/zsh zfree
> > 
> > [ Probing a library function using function name ]
> > perf probe -x /lib64/libc.so.6 malloc
> > 
> > [ list probe-able functions in an executable ]
> > perf probe -F -x /bin/zsh
> > 
> > [ list probe-able functions in an library]
> > perf probe -F -x /lib/libc.so.6
> 
> Can we avoid the need for -x? I.e. we could figure out it is userspace
> and act accordingly.
> 

To list the functions in the module ipv6, we use "perf probe -F -m ipv6"
So I used the same logic to use -x for specifying executables.


This is in agreement with probepoint addition where without any
additional options would mean kernel probepoint; m option would mean
module and x option would mean user space executable. 

However if you still think we should change, do let me know.

-- 
Thanks and Regards
Srikar

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] perf/probe: Provide perf interface for uprobes
  2012-04-11 17:12     ` Srikar Dronamraju
@ 2012-04-11 18:17       ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-04-11 18:17 UTC (permalink / raw)
  To: Srikar Dronamraju
  Cc: Peter Zijlstra, Ingo Molnar, Andrew Morton, Linus Torvalds,
	Ananth N Mavinakayanahalli, Jim Keniston, LKML, Linux-mm,
	Oleg Nesterov, Andi Kleen, Christoph Hellwig, Steven Rostedt,
	Masami Hiramatsu, Thomas Gleixner, Anton Arapov

Em Wed, Apr 11, 2012 at 10:42:25PM +0530, Srikar Dronamraju escreveu:
> * Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-11 11:49:18]:
> > Em Wed, Apr 11, 2012 at 07:27:42PM +0530, Srikar Dronamraju escreveu:
> > > From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
> > > 
> > > - Enhances perf to probe user space executables and libraries.
> > > - Enhances -F/--funcs option of "perf probe" to list possible probe points in
> > >   an executable file or library.
> > > - Documents userspace probing support in perf.
> > > 
> > > [ Probing a function in the executable using function name  ]
> > > perf probe -x /bin/zsh zfree
> > 
> > Can we avoid the need for -x? I.e. we could figure out it is userspace
> > and act accordingly.
> 
> To list the functions in the module ipv6, we use "perf probe -F -m ipv6"
> So I used the same logic to use -x for specifying executables.
> 
> This is in agreement with probepoint addition where without any
> additional options would mean kernel probepoint; m option would mean
> module and x option would mean user space executable. 
> 
> However if you still think we should change, do let me know.

Yeah, if one needs to disambiguate, sure, use these keywords, but for
things like:

$ perf probe /lib/libc.so.6 malloc

I think it is easy to figure out it is userspace. I.e. some regex would
figure it out.

Anyway this can be done in a follow up patch.

- Arnaldo

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-11 18:17       ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-04-11 18:17 UTC (permalink / raw)
  To: Srikar Dronamraju
  Cc: Peter Zijlstra, Ingo Molnar, Andrew Morton, Linus Torvalds,
	Ananth N Mavinakayanahalli, Jim Keniston, LKML, Linux-mm,
	Oleg Nesterov, Andi Kleen, Christoph Hellwig, Steven Rostedt,
	Masami Hiramatsu, Thomas Gleixner, Anton Arapov

Em Wed, Apr 11, 2012 at 10:42:25PM +0530, Srikar Dronamraju escreveu:
> * Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-11 11:49:18]:
> > Em Wed, Apr 11, 2012 at 07:27:42PM +0530, Srikar Dronamraju escreveu:
> > > From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
> > > 
> > > - Enhances perf to probe user space executables and libraries.
> > > - Enhances -F/--funcs option of "perf probe" to list possible probe points in
> > >   an executable file or library.
> > > - Documents userspace probing support in perf.
> > > 
> > > [ Probing a function in the executable using function name  ]
> > > perf probe -x /bin/zsh zfree
> > 
> > Can we avoid the need for -x? I.e. we could figure out it is userspace
> > and act accordingly.
> 
> To list the functions in the module ipv6, we use "perf probe -F -m ipv6"
> So I used the same logic to use -x for specifying executables.
> 
> This is in agreement with probepoint addition where without any
> additional options would mean kernel probepoint; m option would mean
> module and x option would mean user space executable. 
> 
> However if you still think we should change, do let me know.

Yeah, if one needs to disambiguate, sure, use these keywords, but for
things like:

$ perf probe /lib/libc.so.6 malloc

I think it is easy to figure out it is userspace. I.e. some regex would
figure it out.

Anyway this can be done in a follow up patch.

- Arnaldo

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Re: [PATCH] perf/probe: Provide perf interface for uprobes
  2012-04-11 18:17       ` Arnaldo Carvalho de Melo
@ 2012-04-12  3:27         ` Masami Hiramatsu
  -1 siblings, 0 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2012-04-12  3:27 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

(2012/04/12 3:17), Arnaldo Carvalho de Melo wrote:
> Em Wed, Apr 11, 2012 at 10:42:25PM +0530, Srikar Dronamraju escreveu:
>> * Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-11 11:49:18]:
>>> Em Wed, Apr 11, 2012 at 07:27:42PM +0530, Srikar Dronamraju escreveu:
>>>> From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
>>>>
>>>> - Enhances perf to probe user space executables and libraries.
>>>> - Enhances -F/--funcs option of "perf probe" to list possible probe points in
>>>>   an executable file or library.
>>>> - Documents userspace probing support in perf.
>>>>
>>>> [ Probing a function in the executable using function name  ]
>>>> perf probe -x /bin/zsh zfree
>>>
>>> Can we avoid the need for -x? I.e. we could figure out it is userspace
>>> and act accordingly.
>>
>> To list the functions in the module ipv6, we use "perf probe -F -m ipv6"
>> So I used the same logic to use -x for specifying executables.
>>
>> This is in agreement with probepoint addition where without any
>> additional options would mean kernel probepoint; m option would mean
>> module and x option would mean user space executable. 
>>
>> However if you still think we should change, do let me know.
> 
> Yeah, if one needs to disambiguate, sure, use these keywords, but for
> things like:
> 
> $ perf probe /lib/libc.so.6 malloc
> 
> I think it is easy to figure out it is userspace. I.e. some regex would
> figure it out.

That's interessting to me too. Maybe it is also useful syntax for
module specifying too.

e.g.
  perf probe -m kvm kvm_timer_fn

can be

  perf probe kvm.ko kvm_timer_fn

(.ko is required) or if unloaded

  perf probe /lib/modules/XXX/kernel/virt/kvm.ko kvm_timer_fn

Thanks!

-- 
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Re: [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-12  3:27         ` Masami Hiramatsu
  0 siblings, 0 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2012-04-12  3:27 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

(2012/04/12 3:17), Arnaldo Carvalho de Melo wrote:
> Em Wed, Apr 11, 2012 at 10:42:25PM +0530, Srikar Dronamraju escreveu:
>> * Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-11 11:49:18]:
>>> Em Wed, Apr 11, 2012 at 07:27:42PM +0530, Srikar Dronamraju escreveu:
>>>> From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
>>>>
>>>> - Enhances perf to probe user space executables and libraries.
>>>> - Enhances -F/--funcs option of "perf probe" to list possible probe points in
>>>>   an executable file or library.
>>>> - Documents userspace probing support in perf.
>>>>
>>>> [ Probing a function in the executable using function name  ]
>>>> perf probe -x /bin/zsh zfree
>>>
>>> Can we avoid the need for -x? I.e. we could figure out it is userspace
>>> and act accordingly.
>>
>> To list the functions in the module ipv6, we use "perf probe -F -m ipv6"
>> So I used the same logic to use -x for specifying executables.
>>
>> This is in agreement with probepoint addition where without any
>> additional options would mean kernel probepoint; m option would mean
>> module and x option would mean user space executable. 
>>
>> However if you still think we should change, do let me know.
> 
> Yeah, if one needs to disambiguate, sure, use these keywords, but for
> things like:
> 
> $ perf probe /lib/libc.so.6 malloc
> 
> I think it is easy to figure out it is userspace. I.e. some regex would
> figure it out.

That's interessting to me too. Maybe it is also useful syntax for
module specifying too.

e.g.
  perf probe -m kvm kvm_timer_fn

can be

  perf probe kvm.ko kvm_timer_fn

(.ko is required) or if unloaded

  perf probe /lib/modules/XXX/kernel/virt/kvm.ko kvm_timer_fn

Thanks!

-- 
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Re: [PATCH] perf/probe: Provide perf interface for uprobes
  2012-04-12  3:27         ` Masami Hiramatsu
@ 2012-04-12 14:07           ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-04-12 14:07 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Srikar Dronamraju, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

Em Thu, Apr 12, 2012 at 12:27:47PM +0900, Masami Hiramatsu escreveu:
> > * Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-11 11:49:18]:
> > Yeah, if one needs to disambiguate, sure, use these keywords, but for
> > things like:
> > 
> > $ perf probe /lib/libc.so.6 malloc
> > 
> > I think it is easy to figure out it is userspace. I.e. some regex would
> > figure it out.
> 
> That's interessting to me too. Maybe it is also useful syntax for
> module specifying too.
> 
> e.g.
>   perf probe -m kvm kvm_timer_fn
> 
> can be
> 
>   perf probe kvm.ko kvm_timer_fn
> 
> (.ko is required) or if unloaded
> 
>   perf probe /lib/modules/XXX/kernel/virt/kvm.ko kvm_timer_fn

	It may not even be required, since we can check in /proc/modules
if "kvm" is there and as well if it has a function named "kvm_timer_fn".

	Also probably there is no library or binary on the current
directory with such a name :-)

	Likewise, if we do:

 $ perf probe libc-2.12.so malloc

	It should just figure out it is the /lib64/libc-2.12.so

	Heck, even:

 $ perf probe libc malloc

	Makes it even easier to use.

	Its just when one asks for something that has ambiguities that
the tool should ask the user to be a bit more precise to remove such
ambiguity.

	After all...

[acme@sandy linux]$ locate libc-2.12.so
/home/acme/.debug/lib64/libc-2.12.so
/home/acme/.debug/lib64/libc-2.12.so/293f8b6f5e6cea240d1bb0b47ec269ee91f31673
/home/acme/.debug/lib64/libc-2.12.so/5a7fad9dfcbb67af098a258bc2a20137cc954424
/lib64/libc-2.12.so
/usr/lib/debug/lib64/libc-2.12.so.debug
[acme@sandy linux]$

	Only /lib64/libc-2.12.so is on the ld library path :-)

	And after people really start depending on this tool for day to
day use, they may do like me:

[root@sandy ~]# alias probe="perf probe"
[root@sandy ~]# probe -F | grep skb_queue
skb_queue_head
skb_queue_purge
skb_queue_tail
[root@sandy ~]#

	Which gets it to the shortest possible form:

	$ probe libc malloc

	:-)

	Git has this nice feature that is on the same line of making
things easier for the user:

[acme@sandy linux]$ git fack
git: 'fack' is not a git command. See 'git --help'.

Did you mean this?
	fsck
[acme@sandy linux]$

	Hell, yes, fsck is what I meant! :-)

- Arnaldo

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Re: [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-12 14:07           ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-04-12 14:07 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Srikar Dronamraju, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

Em Thu, Apr 12, 2012 at 12:27:47PM +0900, Masami Hiramatsu escreveu:
> > * Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-11 11:49:18]:
> > Yeah, if one needs to disambiguate, sure, use these keywords, but for
> > things like:
> > 
> > $ perf probe /lib/libc.so.6 malloc
> > 
> > I think it is easy to figure out it is userspace. I.e. some regex would
> > figure it out.
> 
> That's interessting to me too. Maybe it is also useful syntax for
> module specifying too.
> 
> e.g.
>   perf probe -m kvm kvm_timer_fn
> 
> can be
> 
>   perf probe kvm.ko kvm_timer_fn
> 
> (.ko is required) or if unloaded
> 
>   perf probe /lib/modules/XXX/kernel/virt/kvm.ko kvm_timer_fn

	It may not even be required, since we can check in /proc/modules
if "kvm" is there and as well if it has a function named "kvm_timer_fn".

	Also probably there is no library or binary on the current
directory with such a name :-)

	Likewise, if we do:

 $ perf probe libc-2.12.so malloc

	It should just figure out it is the /lib64/libc-2.12.so

	Heck, even:

 $ perf probe libc malloc

	Makes it even easier to use.

	Its just when one asks for something that has ambiguities that
the tool should ask the user to be a bit more precise to remove such
ambiguity.

	After all...

[acme@sandy linux]$ locate libc-2.12.so
/home/acme/.debug/lib64/libc-2.12.so
/home/acme/.debug/lib64/libc-2.12.so/293f8b6f5e6cea240d1bb0b47ec269ee91f31673
/home/acme/.debug/lib64/libc-2.12.so/5a7fad9dfcbb67af098a258bc2a20137cc954424
/lib64/libc-2.12.so
/usr/lib/debug/lib64/libc-2.12.so.debug
[acme@sandy linux]$

	Only /lib64/libc-2.12.so is on the ld library path :-)

	And after people really start depending on this tool for day to
day use, they may do like me:

[root@sandy ~]# alias probe="perf probe"
[root@sandy ~]# probe -F | grep skb_queue
skb_queue_head
skb_queue_purge
skb_queue_tail
[root@sandy ~]#

	Which gets it to the shortest possible form:

	$ probe libc malloc

	:-)

	Git has this nice feature that is on the same line of making
things easier for the user:

[acme@sandy linux]$ git fack
git: 'fack' is not a git command. See 'git --help'.

Did you mean this?
	fsck
[acme@sandy linux]$

	Hell, yes, fsck is what I meant! :-)

- Arnaldo

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Re: [PATCH] perf/probe: Provide perf interface for uprobes
  2012-04-12 14:07           ` Arnaldo Carvalho de Melo
@ 2012-04-12 14:41             ` Srikar Dronamraju
  -1 siblings, 0 replies; 24+ messages in thread
From: Srikar Dronamraju @ 2012-04-12 14:41 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

* Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-12 11:07:51]:

> Em Thu, Apr 12, 2012 at 12:27:47PM +0900, Masami Hiramatsu escreveu:
> > > * Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-11 11:49:18]:
> > > Yeah, if one needs to disambiguate, sure, use these keywords, but for
> > > things like:
> > > 
> > > $ perf probe /lib/libc.so.6 malloc
> > > 
> > > I think it is easy to figure out it is userspace. I.e. some regex would
> > > figure it out.
> > 
> > That's interessting to me too. Maybe it is also useful syntax for
> > module specifying too.
> > 
> > e.g.
> >   perf probe -m kvm kvm_timer_fn
> > 
> > can be
> > 
> >   perf probe kvm.ko kvm_timer_fn
> > 
> > (.ko is required) or if unloaded
> > 
> >   perf probe /lib/modules/XXX/kernel/virt/kvm.ko kvm_timer_fn
> 
> 	It may not even be required, since we can check in /proc/modules
> if "kvm" is there and as well if it has a function named "kvm_timer_fn".
> 
> 	Also probably there is no library or binary on the current
> directory with such a name :-)
> 

> 	Likewise, if we do:
> 
>  $ perf probe libc-2.12.so malloc
> 
> 	It should just figure out it is the /lib64/libc-2.12.so
> 
> 	Heck, even:
> 
>  $ perf probe libc malloc
> 
> 	Makes it even easier to use.
> 
> 	Its just when one asks for something that has ambiguities that
> the tool should ask the user to be a bit more precise to remove such
> ambiguity.
> 
> 	After all...
> 

I do understand/agree that the short form looks better. However each
user in the system might have different library /executable paths (and
different ordering of paths. The session in which perf is called may
find just one unique library or executable. But the used binary maynot
be the one that is being traced.

For example: I may have my perf in /home/srikar/bin/perf which may be
picked up. But when I use "perf probe perf cmd_probe" as a root user,
the root may only see /usr/bin/perf. It might look intuitive for us.
However it may not look so for ordinary users and system admins. 

The other choice would be to probe all executables/libraries by the give
name. Here also getting a exhaustive list is debatable.

So I think its okay for people to type a bit more than allow perf to guess
and make a wrong choice. After all we have bash history and tab
completion, command alias to lessen the typing.


> [acme@sandy linux]$ locate libc-2.12.so
> /home/acme/.debug/lib64/libc-2.12.so
> /home/acme/.debug/lib64/libc-2.12.so/293f8b6f5e6cea240d1bb0b47ec269ee91f31673
> /home/acme/.debug/lib64/libc-2.12.so/5a7fad9dfcbb67af098a258bc2a20137cc954424
> /lib64/libc-2.12.so
> /usr/lib/debug/lib64/libc-2.12.so.debug
> [acme@sandy linux]$
> 
> 	Only /lib64/libc-2.12.so is on the ld library path :-)
> 
> 	And after people really start depending on this tool for day to
> day use, they may do like me:

But what if the /lib/libc.so.6 is around on the same machine to cater for 32
bit apps and the user only wanted to trace 32 bit apps.

As you pointed out earlier, some user might have a text file by name
libc in the current directory which he inadvertently could have given
execute permissions. 

-- 
Thanks and Regards
Srikar


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Re: [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-12 14:41             ` Srikar Dronamraju
  0 siblings, 0 replies; 24+ messages in thread
From: Srikar Dronamraju @ 2012-04-12 14:41 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

* Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-12 11:07:51]:

> Em Thu, Apr 12, 2012 at 12:27:47PM +0900, Masami Hiramatsu escreveu:
> > > * Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-11 11:49:18]:
> > > Yeah, if one needs to disambiguate, sure, use these keywords, but for
> > > things like:
> > > 
> > > $ perf probe /lib/libc.so.6 malloc
> > > 
> > > I think it is easy to figure out it is userspace. I.e. some regex would
> > > figure it out.
> > 
> > That's interessting to me too. Maybe it is also useful syntax for
> > module specifying too.
> > 
> > e.g.
> >   perf probe -m kvm kvm_timer_fn
> > 
> > can be
> > 
> >   perf probe kvm.ko kvm_timer_fn
> > 
> > (.ko is required) or if unloaded
> > 
> >   perf probe /lib/modules/XXX/kernel/virt/kvm.ko kvm_timer_fn
> 
> 	It may not even be required, since we can check in /proc/modules
> if "kvm" is there and as well if it has a function named "kvm_timer_fn".
> 
> 	Also probably there is no library or binary on the current
> directory with such a name :-)
> 

> 	Likewise, if we do:
> 
>  $ perf probe libc-2.12.so malloc
> 
> 	It should just figure out it is the /lib64/libc-2.12.so
> 
> 	Heck, even:
> 
>  $ perf probe libc malloc
> 
> 	Makes it even easier to use.
> 
> 	Its just when one asks for something that has ambiguities that
> the tool should ask the user to be a bit more precise to remove such
> ambiguity.
> 
> 	After all...
> 

I do understand/agree that the short form looks better. However each
user in the system might have different library /executable paths (and
different ordering of paths. The session in which perf is called may
find just one unique library or executable. But the used binary maynot
be the one that is being traced.

For example: I may have my perf in /home/srikar/bin/perf which may be
picked up. But when I use "perf probe perf cmd_probe" as a root user,
the root may only see /usr/bin/perf. It might look intuitive for us.
However it may not look so for ordinary users and system admins. 

The other choice would be to probe all executables/libraries by the give
name. Here also getting a exhaustive list is debatable.

So I think its okay for people to type a bit more than allow perf to guess
and make a wrong choice. After all we have bash history and tab
completion, command alias to lessen the typing.


> [acme@sandy linux]$ locate libc-2.12.so
> /home/acme/.debug/lib64/libc-2.12.so
> /home/acme/.debug/lib64/libc-2.12.so/293f8b6f5e6cea240d1bb0b47ec269ee91f31673
> /home/acme/.debug/lib64/libc-2.12.so/5a7fad9dfcbb67af098a258bc2a20137cc954424
> /lib64/libc-2.12.so
> /usr/lib/debug/lib64/libc-2.12.so.debug
> [acme@sandy linux]$
> 
> 	Only /lib64/libc-2.12.so is on the ld library path :-)
> 
> 	And after people really start depending on this tool for day to
> day use, they may do like me:

But what if the /lib/libc.so.6 is around on the same machine to cater for 32
bit apps and the user only wanted to trace 32 bit apps.

As you pointed out earlier, some user might have a text file by name
libc in the current directory which he inadvertently could have given
execute permissions. 

-- 
Thanks and Regards
Srikar

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Re: [PATCH] perf/probe: Provide perf interface for uprobes
  2012-04-12 14:07           ` Arnaldo Carvalho de Melo
@ 2012-04-12 15:10             ` Srikar Dronamraju
  -1 siblings, 0 replies; 24+ messages in thread
From: Srikar Dronamraju @ 2012-04-12 15:10 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

>  $ perf probe libc malloc
> 
> 	Makes it even easier to use.
> 
> 	Its just when one asks for something that has ambiguities that
> the tool should ask the user to be a bit more precise to remove such
> ambiguity.
> 
> 	After all...
> 

Another case 
perf probe do_fork clone_flags now looks for variable clone_flags in
kernel function do_fork.

But if we allow to trace perf probe zsh zfree; then 
'perf probe do_fork clone_flags' should it check for do_fork executable
or not? If it does check and finds one, and searches for clone_flags
function and doesnt find, then should it continue with searching the
kernel?

-- 
Thanks and Regards
Srikar


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Re: [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-12 15:10             ` Srikar Dronamraju
  0 siblings, 0 replies; 24+ messages in thread
From: Srikar Dronamraju @ 2012-04-12 15:10 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

>  $ perf probe libc malloc
> 
> 	Makes it even easier to use.
> 
> 	Its just when one asks for something that has ambiguities that
> the tool should ask the user to be a bit more precise to remove such
> ambiguity.
> 
> 	After all...
> 

Another case 
perf probe do_fork clone_flags now looks for variable clone_flags in
kernel function do_fork.

But if we allow to trace perf probe zsh zfree; then 
'perf probe do_fork clone_flags' should it check for do_fork executable
or not? If it does check and finds one, and searches for clone_flags
function and doesnt find, then should it continue with searching the
kernel?

-- 
Thanks and Regards
Srikar

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Re: [PATCH] perf/probe: Provide perf interface for uprobes
  2012-04-12 14:41             ` Srikar Dronamraju
@ 2012-04-12 15:56               ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-04-12 15:56 UTC (permalink / raw)
  To: Srikar Dronamraju
  Cc: Masami Hiramatsu, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

Em Thu, Apr 12, 2012 at 08:11:48PM +0530, Srikar Dronamraju escreveu:
> * Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-12 11:07:51]:
> > Em Thu, Apr 12, 2012 at 12:27:47PM +0900, Masami Hiramatsu escreveu:
> > 	Likewise, if we do:
> > 
> >  $ perf probe libc-2.12.so malloc

> > 	It should just figure out it is the /lib64/libc-2.12.so

> > 	Heck, even:

> >  $ perf probe libc malloc

> > 	Makes it even easier to use.

> > 	Its just when one asks for something that has ambiguities that
> > the tool should ask the user to be a bit more precise to remove such
> > ambiguity.
> 
> I do understand/agree that the short form looks better. However each
> user in the system might have different library /executable paths (and
> different ordering of paths. The session in which perf is called may

Yeah, they might, but not really the common case, right?

People with multiple versions can use the precise, full path form.

> find just one unique library or executable. But the used binary maynot
> be the one that is being traced.
> 
> For example: I may have my perf in /home/srikar/bin/perf which may be
> picked up. But when I use "perf probe perf cmd_probe" as a root user,
> the root may only see /usr/bin/perf. It might look intuitive for us.

Which is what he expects. If root wants one specific perf file it can do
so as:

$ perf probe /home/srikar/bin/perf cmd_probe

> However it may not look so for ordinary users and system admins. 
> 
> The other choice would be to probe all executables/libraries by the give
> name. Here also getting a exhaustive list is debatable.

If a path is not provided, we have to resort to the LD library path and
$PATH, as when we run:

$ perf

the system will use what was configured ($PATH) and the LD library path
to resolve libraries, so should perf probe, that is what I'm suggesting
after all :-)

I.e. just because I have /home/acme/bin/perf and /root/bin/perf and
/usr/bin/perf, possibly all different (distro shipped, last stable,
current one being developed, whatever), we don't _require_ that the full
path be provided, we let the shell do its work in finding the right
binary.
 
> So I think its okay for people to type a bit more than allow perf to guess
> and make a wrong choice. After all we have bash history and tab
> completion, command alias to lessen the typing.

And those are good, but we can do even better by using well established
conventions for finding the right binary/DSO when a path is not
specified ($PATH, $LD_LIBRARY_PATH).
 
> > [acme@sandy linux]$ locate libc-2.12.so
> > /home/acme/.debug/lib64/libc-2.12.so
> > /home/acme/.debug/lib64/libc-2.12.so/293f8b6f5e6cea240d1bb0b47ec269ee91f31673
> > /home/acme/.debug/lib64/libc-2.12.so/5a7fad9dfcbb67af098a258bc2a20137cc954424
> > /lib64/libc-2.12.so
> > /usr/lib/debug/lib64/libc-2.12.so.debug
> > [acme@sandy linux]$
> > 
> > 	Only /lib64/libc-2.12.so is on the ld library path :-)
> > 
> > 	And after people really start depending on this tool for day to
> > day use, they may do like me:
> 
> But what if the /lib/libc.so.6 is around on the same machine to cater for 32
> bit apps and the user only wanted to trace 32 bit apps.
> 
> As you pointed out earlier, some user might have a text file by name
> libc in the current directory which he inadvertently could have given
> execute permissions. 

That case is covered by "if it is ambiguous, ask for more info".

But in the common case asking for "libc" should be really unambiguous.

Another example:

[root@sandy ~]# rpm -e glibc
error: "glibc" specifies multiple packages:
  glibc-2.12-1.47.el6_2.9.x86_64
  glibc-2.12-1.47.el6_2.9.i686
[root@sandy ~]# 

Oops, I better say which one, or use 'rpm --allmatches' to say that I
intend to remove all those glibc packages. 'perf probe' could act just
like that when ambiguities are found.

- Arnaldo

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Re: [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-12 15:56               ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-04-12 15:56 UTC (permalink / raw)
  To: Srikar Dronamraju
  Cc: Masami Hiramatsu, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

Em Thu, Apr 12, 2012 at 08:11:48PM +0530, Srikar Dronamraju escreveu:
> * Arnaldo Carvalho de Melo <acme@infradead.org> [2012-04-12 11:07:51]:
> > Em Thu, Apr 12, 2012 at 12:27:47PM +0900, Masami Hiramatsu escreveu:
> > 	Likewise, if we do:
> > 
> >  $ perf probe libc-2.12.so malloc

> > 	It should just figure out it is the /lib64/libc-2.12.so

> > 	Heck, even:

> >  $ perf probe libc malloc

> > 	Makes it even easier to use.

> > 	Its just when one asks for something that has ambiguities that
> > the tool should ask the user to be a bit more precise to remove such
> > ambiguity.
> 
> I do understand/agree that the short form looks better. However each
> user in the system might have different library /executable paths (and
> different ordering of paths. The session in which perf is called may

Yeah, they might, but not really the common case, right?

People with multiple versions can use the precise, full path form.

> find just one unique library or executable. But the used binary maynot
> be the one that is being traced.
> 
> For example: I may have my perf in /home/srikar/bin/perf which may be
> picked up. But when I use "perf probe perf cmd_probe" as a root user,
> the root may only see /usr/bin/perf. It might look intuitive for us.

Which is what he expects. If root wants one specific perf file it can do
so as:

$ perf probe /home/srikar/bin/perf cmd_probe

> However it may not look so for ordinary users and system admins. 
> 
> The other choice would be to probe all executables/libraries by the give
> name. Here also getting a exhaustive list is debatable.

If a path is not provided, we have to resort to the LD library path and
$PATH, as when we run:

$ perf

the system will use what was configured ($PATH) and the LD library path
to resolve libraries, so should perf probe, that is what I'm suggesting
after all :-)

I.e. just because I have /home/acme/bin/perf and /root/bin/perf and
/usr/bin/perf, possibly all different (distro shipped, last stable,
current one being developed, whatever), we don't _require_ that the full
path be provided, we let the shell do its work in finding the right
binary.
 
> So I think its okay for people to type a bit more than allow perf to guess
> and make a wrong choice. After all we have bash history and tab
> completion, command alias to lessen the typing.

And those are good, but we can do even better by using well established
conventions for finding the right binary/DSO when a path is not
specified ($PATH, $LD_LIBRARY_PATH).
 
> > [acme@sandy linux]$ locate libc-2.12.so
> > /home/acme/.debug/lib64/libc-2.12.so
> > /home/acme/.debug/lib64/libc-2.12.so/293f8b6f5e6cea240d1bb0b47ec269ee91f31673
> > /home/acme/.debug/lib64/libc-2.12.so/5a7fad9dfcbb67af098a258bc2a20137cc954424
> > /lib64/libc-2.12.so
> > /usr/lib/debug/lib64/libc-2.12.so.debug
> > [acme@sandy linux]$
> > 
> > 	Only /lib64/libc-2.12.so is on the ld library path :-)
> > 
> > 	And after people really start depending on this tool for day to
> > day use, they may do like me:
> 
> But what if the /lib/libc.so.6 is around on the same machine to cater for 32
> bit apps and the user only wanted to trace 32 bit apps.
> 
> As you pointed out earlier, some user might have a text file by name
> libc in the current directory which he inadvertently could have given
> execute permissions. 

That case is covered by "if it is ambiguous, ask for more info".

But in the common case asking for "libc" should be really unambiguous.

Another example:

[root@sandy ~]# rpm -e glibc
error: "glibc" specifies multiple packages:
  glibc-2.12-1.47.el6_2.9.x86_64
  glibc-2.12-1.47.el6_2.9.i686
[root@sandy ~]# 

Oops, I better say which one, or use 'rpm --allmatches' to say that I
intend to remove all those glibc packages. 'perf probe' could act just
like that when ambiguities are found.

- Arnaldo

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] perf/probe: Provide perf interface for uprobes
  2012-04-12 15:10             ` Srikar Dronamraju
@ 2012-04-13  6:27               ` Masami Hiramatsu
  -1 siblings, 0 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2012-04-13  6:27 UTC (permalink / raw)
  To: Srikar Dronamraju
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Ingo Molnar,
	Andrew Morton, Linus Torvalds, Ananth N Mavinakayanahalli,
	Jim Keniston, LKML, Linux-mm, Oleg Nesterov, Andi Kleen,
	Christoph Hellwig, Steven Rostedt, Thomas Gleixner, Anton Arapov

(2012/04/13 0:10), Srikar Dronamraju wrote:
>>  $ perf probe libc malloc
>>
>> 	Makes it even easier to use.
>>
>> 	Its just when one asks for something that has ambiguities that
>> the tool should ask the user to be a bit more precise to remove such
>> ambiguity.
>>
>> 	After all...
>>
> 
> Another case 
> perf probe do_fork clone_flags now looks for variable clone_flags in
> kernel function do_fork.
> 
> But if we allow to trace perf probe zsh zfree; then 
> 'perf probe do_fork clone_flags' should it check for do_fork executable
> or not? If it does check and finds one, and searches for clone_flags
> function and doesnt find, then should it continue with searching the
> kernel?
> 

Agree. I'd like to suggest you to start with only full path support,
and see, how we can handle abbreviations :)

Thank you,

-- 
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-13  6:27               ` Masami Hiramatsu
  0 siblings, 0 replies; 24+ messages in thread
From: Masami Hiramatsu @ 2012-04-13  6:27 UTC (permalink / raw)
  To: Srikar Dronamraju
  Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Ingo Molnar,
	Andrew Morton, Linus Torvalds, Ananth N Mavinakayanahalli,
	Jim Keniston, LKML, Linux-mm, Oleg Nesterov, Andi Kleen,
	Christoph Hellwig, Steven Rostedt, Thomas Gleixner, Anton Arapov

(2012/04/13 0:10), Srikar Dronamraju wrote:
>>  $ perf probe libc malloc
>>
>> 	Makes it even easier to use.
>>
>> 	Its just when one asks for something that has ambiguities that
>> the tool should ask the user to be a bit more precise to remove such
>> ambiguity.
>>
>> 	After all...
>>
> 
> Another case 
> perf probe do_fork clone_flags now looks for variable clone_flags in
> kernel function do_fork.
> 
> But if we allow to trace perf probe zsh zfree; then 
> 'perf probe do_fork clone_flags' should it check for do_fork executable
> or not? If it does check and finds one, and searches for clone_flags
> function and doesnt find, then should it continue with searching the
> kernel?
> 

Agree. I'd like to suggest you to start with only full path support,
and see, how we can handle abbreviations :)

Thank you,

-- 
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] perf/probe: Provide perf interface for uprobes
  2012-04-13  6:27               ` Masami Hiramatsu
@ 2012-04-14  1:13                 ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-04-14  1:13 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Srikar Dronamraju, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

Em Fri, Apr 13, 2012 at 03:27:55PM +0900, Masami Hiramatsu escreveu:
> (2012/04/13 0:10), Srikar Dronamraju wrote:
> >>  $ perf probe libc malloc
> >>
> >> 	Makes it even easier to use.
> >>
> >> 	Its just when one asks for something that has ambiguities that
> >> the tool should ask the user to be a bit more precise to remove such
> >> ambiguity.
> >>
> >> 	After all...

> > Another case 
> > perf probe do_fork clone_flags now looks for variable clone_flags in
> > kernel function do_fork.

> > But if we allow to trace perf probe zsh zfree; then 
> > 'perf probe do_fork clone_flags' should it check for do_fork executable
> > or not? If it does check and finds one, and searches for clone_flags
> > function and doesnt find, then should it continue with searching the
> > kernel?

> Agree. I'd like to suggest you to start with only full path support,
> and see, how we can handle abbreviations :)

Agreed, I was just making usability suggestions.

Those can be implemented later, if we agree they ease the tool use.

- Arnaldo

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-14  1:13                 ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 24+ messages in thread
From: Arnaldo Carvalho de Melo @ 2012-04-14  1:13 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Srikar Dronamraju, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

Em Fri, Apr 13, 2012 at 03:27:55PM +0900, Masami Hiramatsu escreveu:
> (2012/04/13 0:10), Srikar Dronamraju wrote:
> >>  $ perf probe libc malloc
> >>
> >> 	Makes it even easier to use.
> >>
> >> 	Its just when one asks for something that has ambiguities that
> >> the tool should ask the user to be a bit more precise to remove such
> >> ambiguity.
> >>
> >> 	After all...

> > Another case 
> > perf probe do_fork clone_flags now looks for variable clone_flags in
> > kernel function do_fork.

> > But if we allow to trace perf probe zsh zfree; then 
> > 'perf probe do_fork clone_flags' should it check for do_fork executable
> > or not? If it does check and finds one, and searches for clone_flags
> > function and doesnt find, then should it continue with searching the
> > kernel?

> Agree. I'd like to suggest you to start with only full path support,
> and see, how we can handle abbreviations :)

Agreed, I was just making usability suggestions.

Those can be implemented later, if we agree they ease the tool use.

- Arnaldo

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] perf/probe: Provide perf interface for uprobes
  2012-04-14  1:13                 ` Arnaldo Carvalho de Melo
@ 2012-04-16 12:27                   ` Srikar Dronamraju
  -1 siblings, 0 replies; 24+ messages in thread
From: Srikar Dronamraju @ 2012-04-16 12:27 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

> 
> > > Another case 
> > > perf probe do_fork clone_flags now looks for variable clone_flags in
> > > kernel function do_fork.
> 
> > > But if we allow to trace perf probe zsh zfree; then 
> > > 'perf probe do_fork clone_flags' should it check for do_fork executable
> > > or not? If it does check and finds one, and searches for clone_flags
> > > function and doesnt find, then should it continue with searching the
> > > kernel?
> 
> > Agree. I'd like to suggest you to start with only full path support,
> > and see, how we can handle abbreviations :)
> 
> Agreed, I was just making usability suggestions.
> 
> Those can be implemented later, if we agree they ease the tool use.
> 

I have just made a prototype for guessing the target when -m and -x
options arent passed. That still uses the absolute path for now.

I was trying to see if we can identify the module by the short name by
using kernel_get_module_path(). However kernel_get_module_path() needs
init_vmlinux() to be called before. Since init_vmlinux() cant be called
more than once and init_vmlinux gets called later, I thought calling it
here wasnt good option. Wanted to see if we could open /proc/modules
and then match the module name.  But again, I wasnt sure how to handle
offline modules.  

-- 
Thanks and Regards
Srikar


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] perf/probe: Provide perf interface for uprobes
@ 2012-04-16 12:27                   ` Srikar Dronamraju
  0 siblings, 0 replies; 24+ messages in thread
From: Srikar Dronamraju @ 2012-04-16 12:27 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Masami Hiramatsu, Peter Zijlstra, Ingo Molnar, Andrew Morton,
	Linus Torvalds, Ananth N Mavinakayanahalli, Jim Keniston, LKML,
	Linux-mm, Oleg Nesterov, Andi Kleen, Christoph Hellwig,
	Steven Rostedt, Thomas Gleixner, Anton Arapov

> 
> > > Another case 
> > > perf probe do_fork clone_flags now looks for variable clone_flags in
> > > kernel function do_fork.
> 
> > > But if we allow to trace perf probe zsh zfree; then 
> > > 'perf probe do_fork clone_flags' should it check for do_fork executable
> > > or not? If it does check and finds one, and searches for clone_flags
> > > function and doesnt find, then should it continue with searching the
> > > kernel?
> 
> > Agree. I'd like to suggest you to start with only full path support,
> > and see, how we can handle abbreviations :)
> 
> Agreed, I was just making usability suggestions.
> 
> Those can be implemented later, if we agree they ease the tool use.
> 

I have just made a prototype for guessing the target when -m and -x
options arent passed. That still uses the absolute path for now.

I was trying to see if we can identify the module by the short name by
using kernel_get_module_path(). However kernel_get_module_path() needs
init_vmlinux() to be called before. Since init_vmlinux() cant be called
more than once and init_vmlinux gets called later, I thought calling it
here wasnt good option. Wanted to see if we could open /proc/modules
and then match the module name.  But again, I wasnt sure how to handle
offline modules.  

-- 
Thanks and Regards
Srikar

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2012-04-16 12:36 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-11 13:57 [PATCH] perf/probe: Provide perf interface for uprobes Srikar Dronamraju
2012-04-11 13:57 ` Srikar Dronamraju
2012-04-11 14:49 ` Arnaldo Carvalho de Melo
2012-04-11 14:49   ` Arnaldo Carvalho de Melo
2012-04-11 17:12   ` Srikar Dronamraju
2012-04-11 17:12     ` Srikar Dronamraju
2012-04-11 18:17     ` Arnaldo Carvalho de Melo
2012-04-11 18:17       ` Arnaldo Carvalho de Melo
2012-04-12  3:27       ` Masami Hiramatsu
2012-04-12  3:27         ` Masami Hiramatsu
2012-04-12 14:07         ` Arnaldo Carvalho de Melo
2012-04-12 14:07           ` Arnaldo Carvalho de Melo
2012-04-12 14:41           ` Srikar Dronamraju
2012-04-12 14:41             ` Srikar Dronamraju
2012-04-12 15:56             ` Arnaldo Carvalho de Melo
2012-04-12 15:56               ` Arnaldo Carvalho de Melo
2012-04-12 15:10           ` Srikar Dronamraju
2012-04-12 15:10             ` Srikar Dronamraju
2012-04-13  6:27             ` Masami Hiramatsu
2012-04-13  6:27               ` Masami Hiramatsu
2012-04-14  1:13               ` Arnaldo Carvalho de Melo
2012-04-14  1:13                 ` Arnaldo Carvalho de Melo
2012-04-16 12:27                 ` Srikar Dronamraju
2012-04-16 12:27                   ` Srikar Dronamraju

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.