All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH -tip 00/10] perf-probe updates - data-structure support, etc.
@ 2010-03-16 22:05 Masami Hiramatsu
  2010-03-16 22:05 ` [PATCH -tip 01/10] perf tools: Introduce xzalloc() for detecting out of memory Masami Hiramatsu
                   ` (10 more replies)
  0 siblings, 11 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-16 22:05 UTC (permalink / raw)
  To: Ingo Molnar, lkml; +Cc: systemtap, DLE

Hi Ingo,

Here are several updates of perf-probe.
This updates includes data structure accessing support
--list option enhancement and --dry-run option support.

- --dry-run allows users to run perf-probe just for checking
  that the command works correctly.

- --list option enhancement allows user to check where the
  probes are put on (with filename/line number).

- data structure accessing support allows user to trace
  the contents of local variables/function parameters.

Long-term TODOs (future features):
  - Enhance probe-finder to decode call frame instructions.
  - Support tracing static variables (non global)
  - Support variable basic types from debuginfo (e.g. char, int, ...)
  - Support array element (var[N])
  - Support string/dynamic arrays (*var, var[N..M])
  - Support the type of return value
  - Support force type-casting ((type)var)
  - Support sys_perf_counter_open (for non-root users)
  - Support dynamic array-indexing (var[var2])

Miscs:
  - Better support for probes on modules
  - More debugger like enhancements(%next, --disasm, etc.)


Thank you,

---

Masami Hiramatsu (10):
      perf probe: Accessing members in data structures
      perf probe: List probes with line number and file name
      perf probe: Introduce kprobe_trace_event and perf_probe_event
      perf probe: Add --dry-run option
      perf probe: Introduce die_find_child() function
      perf probe: Rename some die_get_* functions
      perf probe: Rename session to param
      perf probe: Move add-probe routine under util/
      perf probe: Use wrapper functions
      perf tools: Introduce xzalloc() for detecting out of memory


 tools/perf/Documentation/perf-probe.txt |    5 
 tools/perf/builtin-probe.c              |  191 +------
 tools/perf/util/probe-event.c           |  830 +++++++++++++++++++++++--------
 tools/perf/util/probe-event.h           |  123 ++++-
 tools/perf/util/probe-finder.c          |  459 ++++++++++++-----
 tools/perf/util/probe-finder.h          |   60 +-
 tools/perf/util/util.h                  |    7 
 7 files changed, 1115 insertions(+), 560 deletions(-)

-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* [PATCH -tip 01/10] perf tools: Introduce xzalloc() for detecting out of memory
  2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
@ 2010-03-16 22:05 ` Masami Hiramatsu
  2010-03-17 11:27   ` [tip:perf/core] perf tools: Introduce xzalloc() for detecting out of memory conditions tip-bot for Masami Hiramatsu
  2010-03-16 22:05 ` [PATCH -tip 02/10] perf probe: Use wrapper functions Masami Hiramatsu
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-16 22:05 UTC (permalink / raw)
  To: Ingo Molnar, lkml
  Cc: systemtap, DLE, Masami Hiramatsu, Ingo Molnar,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Paul Mackerras,
	Mike Galbraith, Peter Zijlstra

Introducing xzalloc() which wrapping zalloc() for detecting out of memory.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
---

 tools/perf/util/util.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 0f5b2a6..630902e 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -295,6 +295,13 @@ extern void *xmemdupz(const void *data, size_t len);
 extern char *xstrndup(const char *str, size_t len);
 extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
 
+static inline void *xzalloc(size_t size)
+{
+	void *buf;
+	buf = xmalloc(size);
+	return memset(buf, 0, size);
+}
+
 static inline void *zalloc(size_t size)
 {
 	return calloc(1, size);


-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* [PATCH -tip 02/10] perf probe: Use wrapper functions
  2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
  2010-03-16 22:05 ` [PATCH -tip 01/10] perf tools: Introduce xzalloc() for detecting out of memory Masami Hiramatsu
@ 2010-03-16 22:05 ` Masami Hiramatsu
  2010-03-17 11:27   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2010-03-16 22:05 ` [PATCH -tip 03/10] perf probe: Move add-probe routine under util/ Masami Hiramatsu
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-16 22:05 UTC (permalink / raw)
  To: Ingo Molnar, lkml
  Cc: systemtap, DLE, Masami Hiramatsu, Ingo Molnar,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Paul Mackerras,
	Mike Galbraith, Peter Zijlstra

Use wrapperf functions as much as possible, to check out of memory
in perf probe.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
---

 tools/perf/builtin-probe.c     |    4 +--
 tools/perf/util/probe-event.c  |   46 +++++++++++++++-------------------------
 tools/perf/util/probe-finder.c |   14 +++++-------
 3 files changed, 24 insertions(+), 40 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 152d6c9..b6afe7b 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -87,9 +87,7 @@ static void parse_probe_event_argv(int argc, const char **argv)
 	len = 0;
 	for (i = 0; i < argc; i++)
 		len += strlen(argv[i]) + 1;
-	buf = zalloc(len + 1);
-	if (!buf)
-		die("Failed to allocate memory for binding arguments.");
+	buf = xzalloc(len + 1);
 	len = 0;
 	for (i = 0; i < argc; i++)
 		len += sprintf(&buf[len], "%s ", argv[i]);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 7c004b6..88a3b6d 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -33,6 +33,7 @@
 #include <limits.h>
 
 #undef _GNU_SOURCE
+#include "util.h"
 #include "event.h"
 #include "string.h"
 #include "strlist.h"
@@ -90,9 +91,9 @@ void parse_line_range_desc(const char *arg, struct line_range *lr)
 		if (*tmp != '\0')
 			semantic_error("Tailing with invalid character '%d'.",
 				       *tmp);
-		tmp = strndup(arg, (ptr - arg));
+		tmp = xstrndup(arg, (ptr - arg));
 	} else
-		tmp = strdup(arg);
+		tmp = xstrdup(arg);
 
 	if (strchr(tmp, '.'))
 		lr->file = tmp;
@@ -135,7 +136,7 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 		if (!check_event_name(arg))
 			semantic_error("%s is bad for event name -it must "
 				       "follow C symbol-naming rule.", arg);
-		pp->event = strdup(arg);
+		pp->event = xstrdup(arg);
 		arg = tmp;
 	}
 
@@ -147,17 +148,16 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 
 	/* Check arg is function or file and copy it */
 	if (strchr(arg, '.'))	/* File */
-		pp->file = strdup(arg);
+		pp->file = xstrdup(arg);
 	else			/* Function */
-		pp->function = strdup(arg);
-	DIE_IF(pp->file == NULL && pp->function == NULL);
+		pp->function = xstrdup(arg);
 
 	/* Parse other options */
 	while (ptr) {
 		arg = ptr;
 		c = nc;
 		if (c == ';') {	/* Lazy pattern must be the last part */
-			pp->lazy_line = strdup(arg);
+			pp->lazy_line = xstrdup(arg);
 			break;
 		}
 		ptr = strpbrk(arg, ";:+@%");
@@ -181,8 +181,7 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 		case '@':	/* File name */
 			if (pp->file)
 				semantic_error("SRC@SRC is not allowed.");
-			pp->file = strdup(arg);
-			DIE_IF(pp->file == NULL);
+			pp->file = xstrdup(arg);
 			break;
 		case '%':	/* Probe places */
 			if (strcmp(arg, "return") == 0) {
@@ -247,11 +246,9 @@ void parse_perf_probe_event(const char *str, struct probe_point *pp,
 
 	/* Copy arguments and ensure return probe has no C argument */
 	pp->nr_args = argc - 1;
-	pp->args = zalloc(sizeof(char *) * pp->nr_args);
+	pp->args = xzalloc(sizeof(char *) * pp->nr_args);
 	for (i = 0; i < pp->nr_args; i++) {
-		pp->args[i] = strdup(argv[i + 1]);
-		if (!pp->args[i])
-			die("Failed to copy argument.");
+		pp->args[i] = xstrdup(argv[i + 1]);
 		if (is_c_varname(pp->args[i])) {
 			if (pp->retprobe)
 				semantic_error("You can't specify local"
@@ -299,14 +296,12 @@ void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
 	pp->file = NULL;
 
 	pp->nr_args = argc - 2;
-	pp->args = zalloc(sizeof(char *) * pp->nr_args);
+	pp->args = xzalloc(sizeof(char *) * pp->nr_args);
 	for (i = 0; i < pp->nr_args; i++) {
 		p = strchr(argv[i + 2], '=');
 		if (p)	/* We don't need which register is assigned. */
 			*p = '\0';
-		pp->args[i] = strdup(argv[i + 2]);
-		if (!pp->args[i])
-			die("Failed to copy argument.");
+		pp->args[i] = xstrdup(argv[i + 2]);
 	}
 
 	argv_free(argv);
@@ -319,10 +314,8 @@ int synthesize_perf_probe_point(struct probe_point *pp)
 	char offs[64] = "", line[64] = "";
 	int ret;
 
-	pp->probes[0] = buf = zalloc(MAX_CMDLEN);
+	pp->probes[0] = buf = xzalloc(MAX_CMDLEN);
 	pp->found = 1;
-	if (!buf)
-		die("Failed to allocate memory by zalloc.");
 	if (pp->offset) {
 		ret = e_snprintf(offs, 64, "+%d", pp->offset);
 		if (ret <= 0)
@@ -380,9 +373,7 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
 	char *buf;
 	int i, len, ret;
 
-	pp->probes[0] = buf = zalloc(MAX_CMDLEN);
-	if (!buf)
-		die("Failed to allocate memory by zalloc.");
+	pp->probes[0] = buf = xzalloc(MAX_CMDLEN);
 	ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
 	if (ret <= 0)
 		goto error;
@@ -612,10 +603,9 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
 	for (j = 0; j < nr_probes; j++) {
 		pp = probes + j;
 		if (!pp->event)
-			pp->event = strdup(pp->function);
+			pp->event = xstrdup(pp->function);
 		if (!pp->group)
-			pp->group = strdup(PERFPROBE_GROUP);
-		DIE_IF(!pp->event || !pp->group);
+			pp->group = xstrdup(PERFPROBE_GROUP);
 		/* If force_add is true, suffix search is allowed */
 		allow_suffix = force_add;
 		for (i = 0; i < pp->found; i++) {
@@ -709,9 +699,7 @@ void del_trace_kprobe_events(struct strlist *dellist)
 	namelist = get_perf_event_names(fd, true);
 
 	strlist__for_each(ent, dellist) {
-		str = strdup(ent->s);
-		if (!str)
-			die("Failed to copy event.");
+		str = xstrdup(ent->s);
 		pr_debug("Parsing: %s\n", str);
 		p = strchr(str, ':');
 		if (p) {
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c171a24..e887bb6 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -125,8 +125,7 @@ static void line_list__add_line(struct list_head *head, unsigned int line)
 	p = head;
 found:
 	pr_debug("line list: add a line %u\n", line);
-	ln = zalloc(sizeof(struct line_node));
-	DIE_IF(ln == NULL);
+	ln = xzalloc(sizeof(struct line_node));
 	ln->line = line;
 	INIT_LIST_HEAD(&ln->list);
 	list_add(&ln->list, p);
@@ -416,7 +415,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 				(unsigned long)(pf->addr - eaddr));
 		/* Copy the function name if possible */
 		if (!pp->function) {
-			pp->function = strdup(name);
+			pp->function = xstrdup(name);
 			pp->offset = (size_t)(pf->addr - eaddr);
 		}
 	} else {
@@ -425,7 +424,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 			       (uintmax_t)pf->addr);
 		if (!pp->function) {
 			/* TODO: Use _stext */
-			pp->function = strdup("");
+			pp->function = xstrdup("");
 			pp->offset = (size_t)pf->addr;
 		}
 	}
@@ -456,7 +455,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 	if (pp->found == MAX_PROBES)
 		die("Too many( > %d) probe point found.\n", MAX_PROBES);
 
-	pp->probes[pp->found] = strdup(tmp);
+	pp->probes[pp->found] = xstrdup(tmp);
 	pp->found++;
 }
 
@@ -506,8 +505,7 @@ static int find_lazy_match_lines(struct list_head *head,
 	if (fd < 0)
 		die("failed to open %s", fname);
 	DIE_IF(fstat(fd, &st) < 0);
-	fbuf = malloc(st.st_size + 2);
-	DIE_IF(fbuf == NULL);
+	fbuf = xmalloc(st.st_size + 2);
 	DIE_IF(read(fd, fbuf, st.st_size) < 0);
 	close(fd);
 	fbuf[st.st_size] = '\n';	/* Dummy line */
@@ -727,7 +725,7 @@ static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 
 		/* Copy real path */
 		if (!lf->lr->path)
-			lf->lr->path = strdup(src);
+			lf->lr->path = xstrdup(src);
 		line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
 	}
 	/* Update status */


-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* [PATCH -tip 03/10] perf probe: Move add-probe routine under util/
  2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
  2010-03-16 22:05 ` [PATCH -tip 01/10] perf tools: Introduce xzalloc() for detecting out of memory Masami Hiramatsu
  2010-03-16 22:05 ` [PATCH -tip 02/10] perf probe: Use wrapper functions Masami Hiramatsu
@ 2010-03-16 22:05 ` Masami Hiramatsu
  2010-03-17 11:28   ` [tip:perf/core] perf probe: Move add-probe routine to util/ tip-bot for Masami Hiramatsu
  2010-03-16 22:05 ` [PATCH -tip 04/10] perf probe: Rename session to param Masami Hiramatsu
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-16 22:05 UTC (permalink / raw)
  To: Ingo Molnar, lkml
  Cc: systemtap, DLE, Masami Hiramatsu, Ingo Molnar,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Paul Mackerras,
	Mike Galbraith, Peter Zijlstra

Move add-probe routine into util/probe_event.c. This simplifies
main routine for reducing maintenance cost.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
---

 tools/perf/builtin-probe.c    |  126 +-------------------------------------
 tools/perf/util/probe-event.c |  137 ++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/probe-event.h |    2 -
 3 files changed, 139 insertions(+), 126 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index b6afe7b..2087034 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -36,11 +36,9 @@
 #include "builtin.h"
 #include "util/util.h"
 #include "util/strlist.h"
-#include "util/event.h"
+#include "util/symbol.h"
 #include "util/debug.h"
 #include "util/debugfs.h"
-#include "util/symbol.h"
-#include "util/thread.h"
 #include "util/parse-options.h"
 #include "util/parse-events.h"	/* For debugfs_path */
 #include "util/probe-finder.h"
@@ -57,8 +55,6 @@ static struct {
 	int nr_probe;
 	struct probe_point probes[MAX_PROBES];
 	struct strlist *dellist;
-	struct map_groups kmap_groups;
-	struct map *kmaps[MAP__NR_TYPES];
 	struct line_range line_range;
 } session;
 
@@ -114,29 +110,7 @@ static int opt_del_probe_event(const struct option *opt __used,
 	return 0;
 }
 
-/* Currently just checking function name from symbol map */
-static void evaluate_probe_point(struct probe_point *pp)
-{
-	struct symbol *sym;
-	sym = map__find_symbol_by_name(session.kmaps[MAP__FUNCTION],
-				       pp->function, NULL);
-	if (!sym)
-		die("Kernel symbol \'%s\' not found - probe not added.",
-		    pp->function);
-}
-
 #ifndef NO_DWARF_SUPPORT
-static int open_vmlinux(void)
-{
-	if (map__load(session.kmaps[MAP__FUNCTION], NULL) < 0) {
-		pr_debug("Failed to load kernel map.\n");
-		return -EINVAL;
-	}
-	pr_debug("Try to open %s\n",
-		 session.kmaps[MAP__FUNCTION]->dso->long_name);
-	return open(session.kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
-}
-
 static int opt_show_lines(const struct option *opt __used,
 			  const char *str, int unset __used)
 {
@@ -204,31 +178,8 @@ static const struct option options[] = {
 	OPT_END()
 };
 
-/* Initialize symbol maps for vmlinux */
-static void init_vmlinux(void)
-{
-	symbol_conf.sort_by_name = true;
-	if (symbol_conf.vmlinux_name == NULL)
-		symbol_conf.try_vmlinux_path = true;
-	else
-		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
-	if (symbol__init() < 0)
-		die("Failed to init symbol map.");
-
-	map_groups__init(&session.kmap_groups);
-	if (map_groups__create_kernel_maps(&session.kmap_groups,
-					   session.kmaps) < 0)
-		die("Failed to create kernel maps.");
-}
-
 int cmd_probe(int argc, const char **argv, const char *prefix __used)
 {
-	int i, ret;
-#ifndef NO_DWARF_SUPPORT
-	int fd;
-#endif
-	struct probe_point *pp;
-
 	argc = parse_options(argc, argv, options, probe_usage,
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 	if (argc > 0) {
@@ -267,14 +218,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 				   " --add/--del.\n");
 			usage_with_options(probe_usage, options);
 		}
-		init_vmlinux();
-		fd = open_vmlinux();
-		if (fd < 0)
-			die("Could not open debuginfo file.");
-		ret = find_line_range(fd, &session.line_range);
-		if (ret <= 0)
-			die("Source line is not found.\n");
-		close(fd);
+
 		show_line_range(&session.line_range);
 		return 0;
 	}
@@ -287,72 +231,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			return 0;
 	}
 
-	/* Add probes */
-	init_vmlinux();
-
-	if (session.need_dwarf)
-#ifdef NO_DWARF_SUPPORT
-		die("Debuginfo-analysis is not supported");
-#else	/* !NO_DWARF_SUPPORT */
-		pr_debug("Some probes require debuginfo.\n");
-
-	fd = open_vmlinux();
-	if (fd < 0) {
-		if (session.need_dwarf)
-			die("Could not open debuginfo file.");
-
-		pr_debug("Could not open vmlinux/module file."
-			 " Try to use symbols.\n");
-		goto end_dwarf;
-	}
-
-	/* Searching probe points */
-	for (i = 0; i < session.nr_probe; i++) {
-		pp = &session.probes[i];
-		if (pp->found)
-			continue;
-
-		lseek(fd, SEEK_SET, 0);
-		ret = find_probe_point(fd, pp);
-		if (ret > 0)
-			continue;
-		if (ret == 0) {	/* No error but failed to find probe point. */
-			synthesize_perf_probe_point(pp);
-			die("Probe point '%s' not found. - probe not added.",
-			    pp->probes[0]);
-		}
-		/* Error path */
-		if (session.need_dwarf) {
-			if (ret == -ENOENT)
-				pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
-			die("Could not analyze debuginfo.");
-		}
-		pr_debug("An error occurred in debuginfo analysis."
-			 " Try to use symbols.\n");
-		break;
-	}
-	close(fd);
-
-end_dwarf:
-#endif /* !NO_DWARF_SUPPORT */
-
-	/* Synthesize probes without dwarf */
-	for (i = 0; i < session.nr_probe; i++) {
-		pp = &session.probes[i];
-		if (pp->found)	/* This probe is already found. */
-			continue;
-
-		evaluate_probe_point(pp);
-		ret = synthesize_trace_kprobe_event(pp);
-		if (ret == -E2BIG)
-			die("probe point definition becomes too long.");
-		else if (ret < 0)
-			die("Failed to synthesize a probe point.");
-	}
-
-	/* Settng up probe points */
 	add_trace_kprobe_events(session.probes, session.nr_probe,
-				session.force_add);
+				session.force_add, session.need_dwarf);
 	return 0;
 }
 
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 88a3b6d..1e60a65 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -40,6 +40,8 @@
 #include "debug.h"
 #include "cache.h"
 #include "color.h"
+#include "symbol.h"
+#include "thread.h"
 #include "parse-events.h"  /* For debugfs_path */
 #include "probe-event.h"
 
@@ -65,6 +67,38 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 	return ret;
 }
 
+
+static struct map_groups kmap_groups;
+static struct map *kmaps[MAP__NR_TYPES];
+
+/* Initialize symbol maps for vmlinux */
+static void init_vmlinux(void)
+{
+	symbol_conf.sort_by_name = true;
+	if (symbol_conf.vmlinux_name == NULL)
+		symbol_conf.try_vmlinux_path = true;
+	else
+		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
+	if (symbol__init() < 0)
+		die("Failed to init symbol map.");
+
+	map_groups__init(&kmap_groups);
+	if (map_groups__create_kernel_maps(&kmap_groups, kmaps) < 0)
+		die("Failed to create kernel maps.");
+}
+
+#ifndef NO_DWARF_SUPPORT
+static int open_vmlinux(void)
+{
+	if (map__load(kmaps[MAP__FUNCTION], NULL) < 0) {
+		pr_debug("Failed to load kernel map.\n");
+		return -EINVAL;
+	}
+	pr_debug("Try to open %s\n", kmaps[MAP__FUNCTION]->dso->long_name);
+	return open(kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
+}
+#endif
+
 void parse_line_range_desc(const char *arg, struct line_range *lr)
 {
 	const char *ptr;
@@ -586,8 +620,8 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
 		die("Too many events are on the same function.");
 }
 
-void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
-			     bool force_add)
+static void __add_trace_kprobe_events(struct probe_point *probes,
+				      int nr_probes, bool force_add)
 {
 	int i, j, fd;
 	struct probe_point *pp;
@@ -640,6 +674,92 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
 	close(fd);
 }
 
+/* Currently just checking function name from symbol map */
+static void evaluate_probe_point(struct probe_point *pp)
+{
+	struct symbol *sym;
+	sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
+				       pp->function, NULL);
+	if (!sym)
+		die("Kernel symbol \'%s\' not found - probe not added.",
+		    pp->function);
+}
+
+void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
+			     bool force_add, bool need_dwarf)
+{
+	int i, ret;
+	struct probe_point *pp;
+#ifndef NO_DWARF_SUPPORT
+	int fd;
+#endif
+	/* Add probes */
+	init_vmlinux();
+
+	if (need_dwarf)
+#ifdef NO_DWARF_SUPPORT
+		die("Debuginfo-analysis is not supported");
+#else	/* !NO_DWARF_SUPPORT */
+		pr_debug("Some probes require debuginfo.\n");
+
+	fd = open_vmlinux();
+	if (fd < 0) {
+		if (need_dwarf)
+			die("Could not open debuginfo file.");
+
+		pr_debug("Could not open vmlinux/module file."
+			 " Try to use symbols.\n");
+		goto end_dwarf;
+	}
+
+	/* Searching probe points */
+	for (i = 0; i < nr_probes; i++) {
+		pp = &probes[i];
+		if (pp->found)
+			continue;
+
+		lseek(fd, SEEK_SET, 0);
+		ret = find_probe_point(fd, pp);
+		if (ret > 0)
+			continue;
+		if (ret == 0) {	/* No error but failed to find probe point. */
+			synthesize_perf_probe_point(pp);
+			die("Probe point '%s' not found. - probe not added.",
+			    pp->probes[0]);
+		}
+		/* Error path */
+		if (need_dwarf) {
+			if (ret == -ENOENT)
+				pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
+			die("Could not analyze debuginfo.");
+		}
+		pr_debug("An error occurred in debuginfo analysis."
+			 " Try to use symbols.\n");
+		break;
+	}
+	close(fd);
+
+end_dwarf:
+#endif /* !NO_DWARF_SUPPORT */
+
+	/* Synthesize probes without dwarf */
+	for (i = 0; i < nr_probes; i++) {
+		pp = &probes[i];
+		if (pp->found)	/* This probe is already found. */
+			continue;
+
+		evaluate_probe_point(pp);
+		ret = synthesize_trace_kprobe_event(pp);
+		if (ret == -E2BIG)
+			die("probe point definition becomes too long.");
+		else if (ret < 0)
+			die("Failed to synthesize a probe point.");
+	}
+
+	/* Settng up probe points */
+	__add_trace_kprobe_events(probes, nr_probes, force_add);
+}
+
 static void __del_trace_kprobe_event(int fd, struct str_node *ent)
 {
 	char *p;
@@ -759,6 +879,17 @@ void show_line_range(struct line_range *lr)
 	unsigned int l = 1;
 	struct line_node *ln;
 	FILE *fp;
+	int fd, ret;
+
+	/* Search a line range */
+	init_vmlinux();
+	fd = open_vmlinux();
+	if (fd < 0)
+		die("Could not open debuginfo file.");
+	ret = find_line_range(fd, lr);
+	if (ret <= 0)
+		die("Source line is not found.\n");
+	close(fd);
 
 	setup_pager();
 
@@ -788,3 +919,5 @@ void show_line_range(struct line_range *lr)
 
 	fclose(fp);
 }
+
+
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 711287d..3865e16 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -13,7 +13,7 @@ extern int synthesize_perf_probe_event(struct probe_point *pp);
 extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
 extern int synthesize_trace_kprobe_event(struct probe_point *pp);
 extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
-				    bool force_add);
+				    bool force_add, bool need_dwarf);
 extern void del_trace_kprobe_events(struct strlist *dellist);
 extern void show_perf_probe_events(void);
 extern void show_line_range(struct line_range *lr);


-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* [PATCH -tip 04/10] perf probe: Rename session to param
  2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
                   ` (2 preceding siblings ...)
  2010-03-16 22:05 ` [PATCH -tip 03/10] perf probe: Move add-probe routine under util/ Masami Hiramatsu
@ 2010-03-16 22:05 ` Masami Hiramatsu
  2010-03-17 11:28   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2010-03-16 22:05 ` [PATCH -tip 05/10] perf probe: Rename some die_get_* functions Masami Hiramatsu
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-16 22:05 UTC (permalink / raw)
  To: Ingo Molnar, lkml
  Cc: systemtap, DLE, Masami Hiramatsu, Ingo Molnar,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Paul Mackerras,
	Mike Galbraith, Peter Zijlstra

Since this name 'session' conflicts with 'perf_session', and
this structure just holds parameters anymore.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
---

 tools/perf/builtin-probe.c |   54 ++++++++++++++++++++++----------------------
 1 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 2087034..f577e14 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -56,20 +56,20 @@ static struct {
 	struct probe_point probes[MAX_PROBES];
 	struct strlist *dellist;
 	struct line_range line_range;
-} session;
+} params;
 
 
 /* Parse an event definition. Note that any error must die. */
 static void parse_probe_event(const char *str)
 {
-	struct probe_point *pp = &session.probes[session.nr_probe];
+	struct probe_point *pp = &params.probes[params.nr_probe];
 
-	pr_debug("probe-definition(%d): %s\n", session.nr_probe, str);
-	if (++session.nr_probe == MAX_PROBES)
+	pr_debug("probe-definition(%d): %s\n", params.nr_probe, str);
+	if (++params.nr_probe == MAX_PROBES)
 		die("Too many probes (> %d) are specified.", MAX_PROBES);
 
 	/* Parse perf-probe event into probe_point */
-	parse_perf_probe_event(str, pp, &session.need_dwarf);
+	parse_perf_probe_event(str, pp, &params.need_dwarf);
 
 	pr_debug("%d arguments\n", pp->nr_args);
 }
@@ -103,9 +103,9 @@ static int opt_del_probe_event(const struct option *opt __used,
 			       const char *str, int unset __used)
 {
 	if (str) {
-		if (!session.dellist)
-			session.dellist = strlist__new(true, NULL);
-		strlist__add(session.dellist, str);
+		if (!params.dellist)
+			params.dellist = strlist__new(true, NULL);
+		strlist__add(params.dellist, str);
 	}
 	return 0;
 }
@@ -115,9 +115,9 @@ static int opt_show_lines(const struct option *opt __used,
 			  const char *str, int unset __used)
 {
 	if (str)
-		parse_line_range_desc(str, &session.line_range);
-	INIT_LIST_HEAD(&session.line_range.line_list);
-	session.show_lines = true;
+		parse_line_range_desc(str, &params.line_range);
+	INIT_LIST_HEAD(&params.line_range.line_list);
+	params.show_lines = true;
 	return 0;
 }
 #endif
@@ -140,7 +140,7 @@ static const struct option options[] = {
 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 		   "file", "vmlinux pathname"),
 #endif
-	OPT_BOOLEAN('l', "list", &session.list_events,
+	OPT_BOOLEAN('l', "list", &params.list_events,
 		    "list up current probe events"),
 	OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
 		opt_del_probe_event),
@@ -168,7 +168,7 @@ static const struct option options[] = {
 #endif
 		"\t\t\tkprobe-tracer argument format.)\n",
 		opt_add_probe_event),
-	OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events"
+	OPT_BOOLEAN('f', "force", &params.force_add, "forcibly add events"
 		    " with existing name"),
 #ifndef NO_DWARF_SUPPORT
 	OPT_CALLBACK('L', "line", NULL,
@@ -190,20 +190,20 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		parse_probe_event_argv(argc, argv);
 	}
 
-	if ((!session.nr_probe && !session.dellist && !session.list_events &&
-	     !session.show_lines))
+	if ((!params.nr_probe && !params.dellist && !params.list_events &&
+	     !params.show_lines))
 		usage_with_options(probe_usage, options);
 
 	if (debugfs_valid_mountpoint(debugfs_path) < 0)
 		die("Failed to find debugfs path.");
 
-	if (session.list_events) {
-		if (session.nr_probe != 0 || session.dellist) {
+	if (params.list_events) {
+		if (params.nr_probe != 0 || params.dellist) {
 			pr_warning("  Error: Don't use --list with"
 				   " --add/--del.\n");
 			usage_with_options(probe_usage, options);
 		}
-		if (session.show_lines) {
+		if (params.show_lines) {
 			pr_warning("  Error: Don't use --list with --line.\n");
 			usage_with_options(probe_usage, options);
 		}
@@ -212,27 +212,27 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 	}
 
 #ifndef NO_DWARF_SUPPORT
-	if (session.show_lines) {
-		if (session.nr_probe != 0 || session.dellist) {
+	if (params.show_lines) {
+		if (params.nr_probe != 0 || params.dellist) {
 			pr_warning("  Error: Don't use --line with"
 				   " --add/--del.\n");
 			usage_with_options(probe_usage, options);
 		}
 
-		show_line_range(&session.line_range);
+		show_line_range(&params.line_range);
 		return 0;
 	}
 #endif
 
-	if (session.dellist) {
-		del_trace_kprobe_events(session.dellist);
-		strlist__delete(session.dellist);
-		if (session.nr_probe == 0)
+	if (params.dellist) {
+		del_trace_kprobe_events(params.dellist);
+		strlist__delete(params.dellist);
+		if (params.nr_probe == 0)
 			return 0;
 	}
 
-	add_trace_kprobe_events(session.probes, session.nr_probe,
-				session.force_add, session.need_dwarf);
+	add_trace_kprobe_events(params.probes, params.nr_probe,
+				params.force_add, params.need_dwarf);
 	return 0;
 }
 


-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* [PATCH -tip 05/10] perf probe: Rename some die_get_* functions
  2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
                   ` (3 preceding siblings ...)
  2010-03-16 22:05 ` [PATCH -tip 04/10] perf probe: Rename session to param Masami Hiramatsu
@ 2010-03-16 22:05 ` Masami Hiramatsu
  2010-03-17 11:28   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2010-03-16 22:05 ` [PATCH -tip 06/10] perf probe: Introduce die_find_child() function Masami Hiramatsu
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-16 22:05 UTC (permalink / raw)
  To: Ingo Molnar, lkml
  Cc: systemtap, DLE, Masami Hiramatsu, Ingo Molnar,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Paul Mackerras,
	Mike Galbraith, Peter Zijlstra

Rename die_get_real_subprogram and die_get_inlinefunc to
die_find_real_subprogram and die_find_inlinefunc respectively,
because these functions search its children. After that,
'die_get_' means getting a property of that die, and
'die_find_' means searching DIE-tree to get an appropriate
child die.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
---

 tools/perf/util/probe-finder.c |   16 ++++++++--------
 1 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index e887bb6..c91a960 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -204,8 +204,8 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
 }
 
 /* Search a real subprogram including this line, */
-static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
-					  Dwarf_Die *die_mem)
+static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
+					   Dwarf_Die *die_mem)
 {
 	struct __addr_die_search_param ad;
 	ad.addr = addr;
@@ -218,8 +218,8 @@ static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
 }
 
 /* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
-static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
-				     Dwarf_Die *die_mem)
+static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
+				      Dwarf_Die *die_mem)
 {
 	Dwarf_Die child_die;
 	int ret;
@@ -233,7 +233,7 @@ static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
 		    dwarf_haspc(die_mem, addr))
 			return die_mem;
 
-		if (die_get_inlinefunc(die_mem, addr, &child_die)) {
+		if (die_find_inlinefunc(die_mem, addr, &child_die)) {
 			memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
 			return die_mem;
 		}
@@ -401,7 +401,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 
 	/* If no real subprogram, find a real one */
 	if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
-		sp_die = die_get_real_subprogram(&pf->cu_die,
+		sp_die = die_find_real_subprogram(&pf->cu_die,
 						 pf->addr, &die_mem);
 		if (!sp_die)
 			die("Probe point is not found in subprograms.");
@@ -564,7 +564,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 			if (!dwarf_haspc(sp_die, addr))
 				continue;
 			/* Address filtering 2: No child include addr? */
-			if (die_get_inlinefunc(sp_die, addr, &die_mem))
+			if (die_find_inlinefunc(sp_die, addr, &die_mem))
 				continue;
 		}
 
@@ -714,7 +714,7 @@ static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 				continue;
 
 			/* Address filtering 2: No child include addr? */
-			if (die_get_inlinefunc(sp_die, addr, &die_mem))
+			if (die_find_inlinefunc(sp_die, addr, &die_mem))
 				continue;
 		}
 


-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* [PATCH -tip 06/10] perf probe: Introduce die_find_child() function
  2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
                   ` (4 preceding siblings ...)
  2010-03-16 22:05 ` [PATCH -tip 05/10] perf probe: Rename some die_get_* functions Masami Hiramatsu
@ 2010-03-16 22:05 ` Masami Hiramatsu
  2010-03-17 11:29   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2010-03-16 22:06 ` [PATCH -tip 07/10] perf probe: Add --dry-run option Masami Hiramatsu
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-16 22:05 UTC (permalink / raw)
  To: Ingo Molnar, lkml
  Cc: systemtap, DLE, Masami Hiramatsu, Ingo Molnar,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Paul Mackerras,
	Mike Galbraith, Peter Zijlstra

Introduce die_find_child() function to integrate DIE-tree searching
functions.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
---

 tools/perf/util/probe-finder.c |  136 ++++++++++++++++++++++++----------------
 1 files changed, 80 insertions(+), 56 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c91a960..3942e14 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -186,6 +186,62 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
 	return src;
 }
 
+/* Compare diename and tname */
+static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
+{
+	const char *name;
+	name = dwarf_diename(dw_die);
+	DIE_IF(name == NULL);
+	return strcmp(tname, name);
+}
+
+/* Get entry pc(or low pc, 1st entry of ranges)  of the die */
+static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
+{
+	Dwarf_Addr epc;
+	int ret;
+
+	ret = dwarf_entrypc(dw_die, &epc);
+	DIE_IF(ret == -1);
+	return epc;
+}
+
+/* Return values for die_find callbacks */
+enum {
+	DIE_FIND_CB_FOUND = 0,		/* End of Search */
+	DIE_FIND_CB_CHILD = 1,		/* Search only children */
+	DIE_FIND_CB_SIBLING = 2,	/* Search only siblings */
+	DIE_FIND_CB_CONTINUE = 3,	/* Search children and siblings */
+};
+
+/* Search a child die */
+static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
+				 int (*callback)(Dwarf_Die *, void *),
+				 void *data, Dwarf_Die *die_mem)
+{
+	Dwarf_Die child_die;
+	int ret;
+
+	ret = dwarf_child(rt_die, die_mem);
+	if (ret != 0)
+		return NULL;
+
+	do {
+		ret = callback(die_mem, data);
+		if (ret == DIE_FIND_CB_FOUND)
+			return die_mem;
+
+		if ((ret & DIE_FIND_CB_CHILD) &&
+		    die_find_child(die_mem, callback, data, &child_die)) {
+			memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
+			return die_mem;
+		}
+	} while ((ret & DIE_FIND_CB_SIBLING) &&
+		 dwarf_siblingof(die_mem, die_mem) == 0);
+
+	return NULL;
+}
+
 struct __addr_die_search_param {
 	Dwarf_Addr	addr;
 	Dwarf_Die	*die_mem;
@@ -217,77 +273,45 @@ static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
 		return die_mem;
 }
 
-/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
-static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
-				      Dwarf_Die *die_mem)
+/* die_find callback for inline function search */
+static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
 {
-	Dwarf_Die child_die;
-	int ret;
+	Dwarf_Addr *addr = data;
 
-	ret = dwarf_child(sp_die, die_mem);
-	if (ret != 0)
-		return NULL;
-
-	do {
-		if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
-		    dwarf_haspc(die_mem, addr))
-			return die_mem;
+	if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
+	    dwarf_haspc(die_mem, *addr))
+		return DIE_FIND_CB_FOUND;
 
-		if (die_find_inlinefunc(die_mem, addr, &child_die)) {
-			memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
-			return die_mem;
-		}
-	} while (dwarf_siblingof(die_mem, die_mem) == 0);
-
-	return NULL;
+	return DIE_FIND_CB_CONTINUE;
 }
 
-/* Compare diename and tname */
-static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
+/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
+static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
+				      Dwarf_Die *die_mem)
 {
-	const char *name;
-	name = dwarf_diename(dw_die);
-	DIE_IF(name == NULL);
-	return strcmp(tname, name);
+	return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
 }
 
-/* Get entry pc(or low pc, 1st entry of ranges)  of the die */
-static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
+static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
 {
-	Dwarf_Addr epc;
-	int ret;
+	const char *name = data;
+	int tag;
 
-	ret = dwarf_entrypc(dw_die, &epc);
-	DIE_IF(ret == -1);
-	return epc;
+	tag = dwarf_tag(die_mem);
+	if ((tag == DW_TAG_formal_parameter ||
+	     tag == DW_TAG_variable) &&
+	    (die_compare_name(die_mem, name) == 0))
+		return DIE_FIND_CB_FOUND;
+
+	return DIE_FIND_CB_CONTINUE;
 }
 
-/* Get a variable die */
+/* Find a variable called 'name' */
 static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
 				    Dwarf_Die *die_mem)
 {
-	Dwarf_Die child_die;
-	int tag;
-	int ret;
-
-	ret = dwarf_child(sp_die, die_mem);
-	if (ret != 0)
-		return NULL;
-
-	do {
-		tag = dwarf_tag(die_mem);
-		if ((tag == DW_TAG_formal_parameter ||
-		     tag == DW_TAG_variable) &&
-		    (die_compare_name(die_mem, name) == 0))
-			return die_mem;
-
-		if (die_find_variable(die_mem, name, &child_die)) {
-			memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
-			return die_mem;
-		}
-	} while (dwarf_siblingof(die_mem, die_mem) == 0);
-
-	return NULL;
+	return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
+			      die_mem);
 }
 
 /*


-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* [PATCH -tip 07/10] perf probe: Add --dry-run option
  2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
                   ` (5 preceding siblings ...)
  2010-03-16 22:05 ` [PATCH -tip 06/10] perf probe: Introduce die_find_child() function Masami Hiramatsu
@ 2010-03-16 22:06 ` Masami Hiramatsu
  2010-03-17 11:29   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2010-03-16 22:06 ` [PATCH -tip 08/10] perf probe: Introduce kprobe_trace_event and perf_probe_event Masami Hiramatsu
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-16 22:06 UTC (permalink / raw)
  To: Ingo Molnar, lkml
  Cc: systemtap, DLE, Masami Hiramatsu, Ingo Molnar,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Paul Mackerras,
	Mike Galbraith, Peter Zijlstra

Add --dry-run option for debugging and testing.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
---

 tools/perf/Documentation/perf-probe.txt |    5 +++++
 tools/perf/builtin-probe.c              |    1 +
 tools/perf/util/probe-event.c           |   24 ++++++++++++++++--------
 tools/perf/util/probe-event.h           |    2 ++
 4 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 34202b1..0f944b3 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -57,6 +57,11 @@ OPTIONS
 --force::
 	Forcibly add events with existing name.
 
+-n::
+--dry-run::
+	Dry run. With this option, --add and --del doesn't execute actual
+	adding and removal operations.
+
 PROBE SYNTAX
 ------------
 Probe points are defined by following syntax.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index f577e14..a1a2891 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -175,6 +175,7 @@ static const struct option options[] = {
 		     "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]",
 		     "Show source code lines.", opt_show_lines),
 #endif
+	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_END()
 };
 
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1e60a65..ac41578 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -49,6 +49,8 @@
 #define MAX_PROBE_ARGS 128
 #define PERFPROBE_GROUP "probe"
 
+bool probe_event_dry_run;	/* Dry run flag */
+
 #define semantic_error(msg ...) die("Semantic error :" msg)
 
 /* If there is no space to write, returns -E2BIG. */
@@ -430,7 +432,7 @@ error:
 	return ret;
 }
 
-static int open_kprobe_events(int flags, int mode)
+static int open_kprobe_events(bool readwrite)
 {
 	char buf[PATH_MAX];
 	int ret;
@@ -439,7 +441,11 @@ static int open_kprobe_events(int flags, int mode)
 	if (ret < 0)
 		die("Failed to make kprobe_events path.");
 
-	ret = open(buf, flags, mode);
+	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)
 			die("kprobe_events file does not exist -"
@@ -535,7 +541,7 @@ void show_perf_probe_events(void)
 	setup_pager();
 	memset(&pp, 0, sizeof(pp));
 
-	fd = open_kprobe_events(O_RDONLY, 0);
+	fd = open_kprobe_events(false);
 	rawlist = get_trace_kprobe_event_rawlist(fd);
 	close(fd);
 
@@ -585,9 +591,11 @@ static void write_trace_kprobe_event(int fd, const char *buf)
 	int ret;
 
 	pr_debug("Writing event: %s\n", buf);
-	ret = write(fd, buf, strlen(buf));
-	if (ret <= 0)
-		die("Failed to write event: %s", strerror(errno));
+	if (!probe_event_dry_run) {
+		ret = write(fd, buf, strlen(buf));
+		if (ret <= 0)
+			die("Failed to write event: %s", strerror(errno));
+	}
 }
 
 static void get_new_event_name(char *buf, size_t len, const char *base,
@@ -630,7 +638,7 @@ static void __add_trace_kprobe_events(struct probe_point *probes,
 	struct strlist *namelist;
 	bool allow_suffix;
 
-	fd = open_kprobe_events(O_RDWR, O_APPEND);
+	fd = open_kprobe_events(true);
 	/* Get current event names */
 	namelist = get_perf_event_names(fd, false);
 
@@ -814,7 +822,7 @@ void del_trace_kprobe_events(struct strlist *dellist)
 	struct str_node *ent;
 	struct strlist *namelist;
 
-	fd = open_kprobe_events(O_RDWR, O_APPEND);
+	fd = open_kprobe_events(true);
 	/* Get current event names */
 	namelist = get_perf_event_names(fd, true);
 
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 3865e16..703b887 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -5,6 +5,8 @@
 #include "probe-finder.h"
 #include "strlist.h"
 
+extern bool probe_event_dry_run;
+
 extern void parse_line_range_desc(const char *arg, struct line_range *lr);
 extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
 				   bool *need_dwarf);


-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* [PATCH -tip 08/10] perf probe: Introduce kprobe_trace_event and perf_probe_event
  2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
                   ` (6 preceding siblings ...)
  2010-03-16 22:06 ` [PATCH -tip 07/10] perf probe: Add --dry-run option Masami Hiramatsu
@ 2010-03-16 22:06 ` Masami Hiramatsu
  2010-03-17 11:29   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
                     ` (2 more replies)
  2010-03-16 22:06 ` [PATCH -tip 09/10] perf probe: List probes with line number and file name Masami Hiramatsu
                   ` (2 subsequent siblings)
  10 siblings, 3 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-16 22:06 UTC (permalink / raw)
  To: Ingo Molnar, lkml
  Cc: systemtap, DLE, Masami Hiramatsu, Ingo Molnar,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Paul Mackerras,
	Mike Galbraith, Peter Zijlstra

Introduce kprobe_trace_event and perf_probe_event and replace
old probe_point structure with it. probe_point structure is
not enough flexible nor extensible. New data structures
will help implementing further features.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
---

 tools/perf/builtin-probe.c     |   30 +-
 tools/perf/util/probe-event.c  |  626 ++++++++++++++++++++++++++--------------
 tools/perf/util/probe-event.h  |  111 ++++++-
 tools/perf/util/probe-finder.c |  140 ++++-----
 tools/perf/util/probe-finder.h |   58 +---
 5 files changed, 589 insertions(+), 376 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index a1a2891..e0dafd9 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -48,12 +48,11 @@
 
 /* Session management structure */
 static struct {
-	bool need_dwarf;
 	bool list_events;
 	bool force_add;
 	bool show_lines;
-	int nr_probe;
-	struct probe_point probes[MAX_PROBES];
+	int nevents;
+	struct perf_probe_event events[MAX_PROBES];
 	struct strlist *dellist;
 	struct line_range line_range;
 } params;
@@ -62,16 +61,16 @@ static struct {
 /* Parse an event definition. Note that any error must die. */
 static void parse_probe_event(const char *str)
 {
-	struct probe_point *pp = &params.probes[params.nr_probe];
+	struct perf_probe_event *pev = &params.events[params.nevents];
 
-	pr_debug("probe-definition(%d): %s\n", params.nr_probe, str);
-	if (++params.nr_probe == MAX_PROBES)
+	pr_debug("probe-definition(%d): %s\n", params.nevents, str);
+	if (++params.nevents == MAX_PROBES)
 		die("Too many probes (> %d) are specified.", MAX_PROBES);
 
-	/* Parse perf-probe event into probe_point */
-	parse_perf_probe_event(str, pp, &params.need_dwarf);
+	/* Parse a perf-probe command into event */
+	parse_perf_probe_command(str, pev);
 
-	pr_debug("%d arguments\n", pp->nr_args);
+	pr_debug("%d arguments\n", pev->nargs);
 }
 
 static void parse_probe_event_argv(int argc, const char **argv)
@@ -191,7 +190,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		parse_probe_event_argv(argc, argv);
 	}
 
-	if ((!params.nr_probe && !params.dellist && !params.list_events &&
+	if ((!params.nevents && !params.dellist && !params.list_events &&
 	     !params.show_lines))
 		usage_with_options(probe_usage, options);
 
@@ -199,7 +198,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		die("Failed to find debugfs path.");
 
 	if (params.list_events) {
-		if (params.nr_probe != 0 || params.dellist) {
+		if (params.nevents != 0 || params.dellist) {
 			pr_warning("  Error: Don't use --list with"
 				   " --add/--del.\n");
 			usage_with_options(probe_usage, options);
@@ -214,7 +213,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 
 #ifndef NO_DWARF_SUPPORT
 	if (params.show_lines) {
-		if (params.nr_probe != 0 || params.dellist) {
+		if (params.nevents != 0 || params.dellist) {
 			pr_warning("  Error: Don't use --line with"
 				   " --add/--del.\n");
 			usage_with_options(probe_usage, options);
@@ -226,14 +225,13 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 #endif
 
 	if (params.dellist) {
-		del_trace_kprobe_events(params.dellist);
+		del_perf_probe_events(params.dellist);
 		strlist__delete(params.dellist);
-		if (params.nr_probe == 0)
+		if (params.nevents == 0)
 			return 0;
 	}
 
-	add_trace_kprobe_events(params.probes, params.nr_probe,
-				params.force_add, params.need_dwarf);
+	add_perf_probe_events(params.events, params.nevents, params.force_add);
 	return 0;
 }
 
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index ac41578..b44ddfb 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -44,6 +44,7 @@
 #include "thread.h"
 #include "parse-events.h"  /* For debugfs_path */
 #include "probe-event.h"
+#include "probe-finder.h"
 
 #define MAX_CMDLEN 256
 #define MAX_PROBE_ARGS 128
@@ -150,8 +151,9 @@ static bool check_event_name(const char *name)
 }
 
 /* Parse probepoint definition. */
-static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
+static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 {
+	struct perf_probe_point *pp = &pev->point;
 	char *ptr, *tmp;
 	char c, nc = 0;
 	/*
@@ -172,7 +174,8 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 		if (!check_event_name(arg))
 			semantic_error("%s is bad for event name -it must "
 				       "follow C symbol-naming rule.", arg);
-		pp->event = xstrdup(arg);
+		pev->event = xstrdup(arg);
+		pev->group = NULL;
 		arg = tmp;
 	}
 
@@ -255,57 +258,65 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 		semantic_error("Offset/Line/Lazy pattern can't be used with "
 			       "return probe.");
 
-	pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n",
+	pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
 		 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
 		 pp->lazy_line);
 }
 
-/* Parse perf-probe event definition */
-void parse_perf_probe_event(const char *str, struct probe_point *pp,
-			    bool *need_dwarf)
+/* Parse perf-probe event command */
+void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
 {
 	char **argv;
 	int argc, i;
 
-	*need_dwarf = false;
-
-	argv = argv_split(str, &argc);
+	argv = argv_split(cmd, &argc);
 	if (!argv)
 		die("argv_split failed.");
 	if (argc > MAX_PROBE_ARGS + 1)
 		semantic_error("Too many arguments");
 
 	/* Parse probe point */
-	parse_perf_probe_probepoint(argv[0], pp);
-	if (pp->file || pp->line || pp->lazy_line)
-		*need_dwarf = true;
+	parse_perf_probe_point(argv[0], pev);
 
 	/* Copy arguments and ensure return probe has no C argument */
-	pp->nr_args = argc - 1;
-	pp->args = xzalloc(sizeof(char *) * pp->nr_args);
-	for (i = 0; i < pp->nr_args; i++) {
-		pp->args[i] = xstrdup(argv[i + 1]);
-		if (is_c_varname(pp->args[i])) {
-			if (pp->retprobe)
-				semantic_error("You can't specify local"
-						" variable for kretprobe");
-			*need_dwarf = true;
-		}
+	pev->nargs = argc - 1;
+	pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
+	for (i = 0; i < pev->nargs; i++) {
+		pev->args[i].name = xstrdup(argv[i + 1]);
+		if (is_c_varname(pev->args[i].name) && pev->point.retprobe)
+			semantic_error("You can't specify local variable for"
+				       " kretprobe");
 	}
 
 	argv_free(argv);
 }
 
+/* Return true if this perf_probe_event requires debuginfo */
+bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
+{
+	int i;
+
+	if (pev->point.file || pev->point.line || pev->point.lazy_line)
+		return true;
+
+	for (i = 0; i < pev->nargs; i++)
+		if (is_c_varname(pev->args[i].name))
+			return true;
+
+	return false;
+}
+
 /* Parse kprobe_events event into struct probe_point */
-void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
+void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
 {
+	struct kprobe_trace_point *tp = &tev->point;
 	char pr;
 	char *p;
 	int ret, i, argc;
 	char **argv;
 
-	pr_debug("Parsing kprobe_events: %s\n", str);
-	argv = argv_split(str, &argc);
+	pr_debug("Parsing kprobe_events: %s\n", cmd);
+	argv = argv_split(cmd, &argc);
 	if (!argv)
 		die("argv_split failed.");
 	if (argc < 2)
@@ -313,47 +324,46 @@ void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
 
 	/* Scan event and group name. */
 	ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
-		     &pr, (float *)(void *)&pp->group,
-		     (float *)(void *)&pp->event);
+		     &pr, (float *)(void *)&tev->group,
+		     (float *)(void *)&tev->event);
 	if (ret != 3)
 		semantic_error("Failed to parse event name: %s", argv[0]);
-	pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
+	pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
 
-	pp->retprobe = (pr == 'r');
+	tp->retprobe = (pr == 'r');
 
 	/* Scan function name and offset */
-	ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
-		     &pp->offset);
+	ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol,
+		     &tp->offset);
 	if (ret == 1)
-		pp->offset = 0;
-
-	/* kprobe_events doesn't have this information */
-	pp->line = 0;
-	pp->file = NULL;
+		tp->offset = 0;
 
-	pp->nr_args = argc - 2;
-	pp->args = xzalloc(sizeof(char *) * pp->nr_args);
-	for (i = 0; i < pp->nr_args; i++) {
+	tev->nargs = argc - 2;
+	tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
+	for (i = 0; i < tev->nargs; i++) {
 		p = strchr(argv[i + 2], '=');
 		if (p)	/* We don't need which register is assigned. */
-			*p = '\0';
-		pp->args[i] = xstrdup(argv[i + 2]);
+			*p++ = '\0';
+		else
+			p = argv[i + 2];
+		tev->args[i].name = xstrdup(argv[i + 2]);
+		/* TODO: parse regs and offset */
+		tev->args[i].value = xstrdup(p);
 	}
 
 	argv_free(argv);
 }
 
-/* Synthesize only probe point (not argument) */
-int synthesize_perf_probe_point(struct probe_point *pp)
+/* Compose only probe point (not argument) */
+static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 {
 	char *buf;
 	char offs[64] = "", line[64] = "";
 	int ret;
 
-	pp->probes[0] = buf = xzalloc(MAX_CMDLEN);
-	pp->found = 1;
+	buf = xzalloc(MAX_CMDLEN);
 	if (pp->offset) {
-		ret = e_snprintf(offs, 64, "+%d", pp->offset);
+		ret = e_snprintf(offs, 64, "+%lu", pp->offset);
 		if (ret <= 0)
 			goto error;
 	}
@@ -368,68 +378,209 @@ int synthesize_perf_probe_point(struct probe_point *pp)
 				 offs, pp->retprobe ? "%return" : "", line);
 	else
 		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
-	if (ret <= 0) {
+	if (ret <= 0)
+		goto error;
+
+	return buf;
 error:
-		free(pp->probes[0]);
-		pp->probes[0] = NULL;
-		pp->found = 0;
-	}
-	return ret;
+	die("Failed to synthesize perf probe point: %s", strerror(-ret));
 }
 
-int synthesize_perf_probe_event(struct probe_point *pp)
+#if 0
+char *synthesize_perf_probe_command(struct perf_probe_event *pev)
 {
 	char *buf;
 	int i, len, ret;
 
-	len = synthesize_perf_probe_point(pp);
-	if (len < 0)
-		return 0;
+	buf = synthesize_perf_probe_point(&pev->point);
+	if (!buf)
+		return NULL;
 
-	buf = pp->probes[0];
-	for (i = 0; i < pp->nr_args; i++) {
+	len = strlen(buf);
+	for (i = 0; i < pev->nargs; i++) {
 		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
-				 pp->args[i]);
-		if (ret <= 0)
-			goto error;
+				 pev->args[i].name);
+		if (ret <= 0) {
+			free(buf);
+			return NULL;
+		}
 		len += ret;
 	}
-	pp->found = 1;
 
-	return pp->found;
-error:
-	free(pp->probes[0]);
-	pp->probes[0] = NULL;
+	return buf;
+}
+#endif
+
+static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref,
+					     char **buf, size_t *buflen,
+					     int depth)
+{
+	int ret;
+	if (ref->next) {
+		depth = __synthesize_kprobe_trace_arg_ref(ref->next, buf,
+							 buflen, depth + 1);
+		if (depth < 0)
+			goto out;
+	}
+
+	ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
+	if (ret < 0)
+		depth = ret;
+	else {
+		*buf += ret;
+		*buflen -= ret;
+	}
+out:
+	return depth;
 
-	return ret;
 }
 
-int synthesize_trace_kprobe_event(struct probe_point *pp)
+static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
+				       char *buf, size_t buflen)
 {
+	int ret, depth = 0;
+	char *tmp = buf;
+
+	/* Argument name or separator */
+	if (arg->name)
+		ret = e_snprintf(buf, buflen, " %s=", arg->name);
+	else
+		ret = e_snprintf(buf, buflen, " ");
+	if (ret < 0)
+		return ret;
+	buf += ret;
+	buflen -= ret;
+
+	/* Dereferencing arguments */
+	if (arg->ref) {
+		depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf,
+							  &buflen, 1);
+		if (depth < 0)
+			return depth;
+	}
+
+	/* Print argument value */
+	ret = e_snprintf(buf, buflen, "%s", arg->value);
+	if (ret < 0)
+		return ret;
+	buf += ret;
+	buflen -= ret;
+
+	/* Closing */
+	while (depth--) {
+		ret = e_snprintf(buf, buflen, ")");
+		if (ret < 0)
+			return ret;
+		buf += ret;
+		buflen -= ret;
+	}
+
+	return buf - tmp;
+}
+
+char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev)
+{
+	struct kprobe_trace_point *tp = &tev->point;
 	char *buf;
 	int i, len, ret;
 
-	pp->probes[0] = buf = xzalloc(MAX_CMDLEN);
-	ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
-	if (ret <= 0)
+	buf = xzalloc(MAX_CMDLEN);
+	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu",
+			 tp->retprobe ? 'r' : 'p',
+			 tev->group, tev->event,
+			 tp->symbol, tp->offset);
+	if (len <= 0)
 		goto error;
-	len = ret;
 
-	for (i = 0; i < pp->nr_args; i++) {
-		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
-				 pp->args[i]);
+	for (i = 0; i < tev->nargs; i++) {
+		ret = synthesize_kprobe_trace_arg(&tev->args[i], buf + len,
+						  MAX_CMDLEN - len);
 		if (ret <= 0)
 			goto error;
 		len += ret;
 	}
-	pp->found = 1;
 
-	return pp->found;
+	return buf;
 error:
-	free(pp->probes[0]);
-	pp->probes[0] = NULL;
+	free(buf);
+	return NULL;
+}
 
-	return ret;
+void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
+				 struct perf_probe_event *pev)
+{
+	char buf[64];
+	int i;
+
+	pev->event = xstrdup(tev->event);
+	pev->group = xstrdup(tev->group);
+
+	/* Convert trace_point to probe_point */
+	pev->point.function = xstrdup(tev->point.symbol);
+	pev->point.offset = tev->point.offset;
+	pev->point.retprobe = tev->point.retprobe;
+
+	/* Convert trace_arg to probe_arg */
+	pev->nargs = tev->nargs;
+	pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
+	for (i = 0; i < tev->nargs; i++)
+		if (tev->args[i].name)
+			pev->args[i].name = xstrdup(tev->args[i].name);
+		else {
+			synthesize_kprobe_trace_arg(&tev->args[i], buf, 64);
+			pev->args[i].name = xstrdup(buf);
+		}
+}
+
+void clear_perf_probe_event(struct perf_probe_event *pev)
+{
+	struct perf_probe_point *pp = &pev->point;
+	int i;
+
+	if (pev->event)
+		free(pev->event);
+	if (pev->group)
+		free(pev->group);
+	if (pp->file)
+		free(pp->file);
+	if (pp->function)
+		free(pp->function);
+	if (pp->lazy_line)
+		free(pp->lazy_line);
+	for (i = 0; i < pev->nargs; i++)
+		if (pev->args[i].name)
+			free(pev->args[i].name);
+	if (pev->args)
+		free(pev->args);
+	memset(pev, 0, sizeof(*pev));
+}
+
+void clear_kprobe_trace_event(struct kprobe_trace_event *tev)
+{
+	struct kprobe_trace_arg_ref *ref, *next;
+	int i;
+
+	if (tev->event)
+		free(tev->event);
+	if (tev->group)
+		free(tev->group);
+	if (tev->point.symbol)
+		free(tev->point.symbol);
+	for (i = 0; i < tev->nargs; i++) {
+		if (tev->args[i].name)
+			free(tev->args[i].name);
+		if (tev->args[i].value)
+			free(tev->args[i].value);
+		ref = tev->args[i].ref;
+		while (ref) {
+			next = ref->next;
+			free(ref);
+			ref = next;
+		}
+	}
+	if (tev->args)
+		free(tev->args);
+	memset(tev, 0, sizeof(*tev));
 }
 
 static int open_kprobe_events(bool readwrite)
@@ -458,7 +609,7 @@ static int open_kprobe_events(bool readwrite)
 }
 
 /* Get raw string list of current kprobe_events */
-static struct strlist *get_trace_kprobe_event_rawlist(int fd)
+static struct strlist *get_kprobe_trace_command_rawlist(int fd)
 {
 	int ret, idx;
 	FILE *fp;
@@ -486,99 +637,82 @@ static struct strlist *get_trace_kprobe_event_rawlist(int fd)
 	return sl;
 }
 
-/* Free and zero clear probe_point */
-static void clear_probe_point(struct probe_point *pp)
-{
-	int i;
-
-	if (pp->event)
-		free(pp->event);
-	if (pp->group)
-		free(pp->group);
-	if (pp->function)
-		free(pp->function);
-	if (pp->file)
-		free(pp->file);
-	if (pp->lazy_line)
-		free(pp->lazy_line);
-	for (i = 0; i < pp->nr_args; i++)
-		free(pp->args[i]);
-	if (pp->args)
-		free(pp->args);
-	for (i = 0; i < pp->found; i++)
-		free(pp->probes[i]);
-	memset(pp, 0, sizeof(*pp));
-}
-
 /* Show an event */
-static void show_perf_probe_event(const char *event, const char *place,
-				  struct probe_point *pp)
+static void show_perf_probe_event(struct perf_probe_event *pev)
 {
 	int i, ret;
 	char buf[128];
+	char *place;
 
-	ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
+	/* Synthesize only event probe point */
+	place = synthesize_perf_probe_point(&pev->point);
+
+	ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
 	if (ret < 0)
 		die("Failed to copy event: %s", strerror(-ret));
 	printf("  %-40s (on %s", buf, place);
 
-	if (pp->nr_args > 0) {
+	if (pev->nargs > 0) {
 		printf(" with");
-		for (i = 0; i < pp->nr_args; i++)
-			printf(" %s", pp->args[i]);
+		for (i = 0; i < pev->nargs; i++)
+			printf(" %s", pev->args[i].name);
 	}
 	printf(")\n");
+	free(place);
 }
 
 /* List up current perf-probe events */
 void show_perf_probe_events(void)
 {
 	int fd;
-	struct probe_point pp;
+	struct kprobe_trace_event tev;
+	struct perf_probe_event pev;
 	struct strlist *rawlist;
 	struct str_node *ent;
 
 	setup_pager();
-	memset(&pp, 0, sizeof(pp));
+
+	memset(&tev, 0, sizeof(tev));
+	memset(&pev, 0, sizeof(pev));
 
 	fd = open_kprobe_events(false);
-	rawlist = get_trace_kprobe_event_rawlist(fd);
+	rawlist = get_kprobe_trace_command_rawlist(fd);
 	close(fd);
 
 	strlist__for_each(ent, rawlist) {
-		parse_trace_kprobe_event(ent->s, &pp);
-		/* Synthesize only event probe point */
-		synthesize_perf_probe_point(&pp);
+		parse_kprobe_trace_command(ent->s, &tev);
+		convert_to_perf_probe_event(&tev, &pev);
 		/* Show an event */
-		show_perf_probe_event(pp.event, pp.probes[0], &pp);
-		clear_probe_point(&pp);
+		show_perf_probe_event(&pev);
+		clear_perf_probe_event(&pev);
+		clear_kprobe_trace_event(&tev);
 	}
 
 	strlist__delete(rawlist);
 }
 
 /* Get current perf-probe event names */
-static struct strlist *get_perf_event_names(int fd, bool include_group)
+static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
 {
 	char buf[128];
 	struct strlist *sl, *rawlist;
 	struct str_node *ent;
-	struct probe_point pp;
+	struct kprobe_trace_event tev;
 
-	memset(&pp, 0, sizeof(pp));
-	rawlist = get_trace_kprobe_event_rawlist(fd);
+	memset(&tev, 0, sizeof(tev));
 
+	rawlist = get_kprobe_trace_command_rawlist(fd);
 	sl = strlist__new(true, NULL);
 	strlist__for_each(ent, rawlist) {
-		parse_trace_kprobe_event(ent->s, &pp);
+		parse_kprobe_trace_command(ent->s, &tev);
 		if (include_group) {
-			if (e_snprintf(buf, 128, "%s:%s", pp.group,
-				       pp.event) < 0)
+			if (e_snprintf(buf, 128, "%s:%s", tev.group,
+				       tev.event) < 0)
 				die("Failed to copy group:event name.");
 			strlist__add(sl, buf);
 		} else
-			strlist__add(sl, pp.event);
-		clear_probe_point(&pp);
+			strlist__add(sl, tev.event);
+		clear_kprobe_trace_event(&tev);
 	}
 
 	strlist__delete(rawlist);
@@ -586,9 +720,10 @@ static struct strlist *get_perf_event_names(int fd, bool include_group)
 	return sl;
 }
 
-static void write_trace_kprobe_event(int fd, const char *buf)
+static void write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev)
 {
 	int ret;
+	char *buf = synthesize_kprobe_trace_command(tev);
 
 	pr_debug("Writing event: %s\n", buf);
 	if (!probe_event_dry_run) {
@@ -596,6 +731,7 @@ static void write_trace_kprobe_event(int fd, const char *buf)
 		if (ret <= 0)
 			die("Failed to write event: %s", strerror(errno));
 	}
+	free(buf);
 }
 
 static void get_new_event_name(char *buf, size_t len, const char *base,
@@ -628,81 +764,83 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
 		die("Too many events are on the same function.");
 }
 
-static void __add_trace_kprobe_events(struct probe_point *probes,
-				      int nr_probes, bool force_add)
+static void __add_kprobe_trace_events(struct perf_probe_event *pev,
+				      struct kprobe_trace_event *tevs,
+				      int ntevs, bool allow_suffix)
 {
-	int i, j, fd;
-	struct probe_point *pp;
-	char buf[MAX_CMDLEN];
-	char event[64];
+	int i, fd;
+	struct kprobe_trace_event *tev;
+	char buf[64];
+	const char *event, *group;
 	struct strlist *namelist;
-	bool allow_suffix;
 
 	fd = open_kprobe_events(true);
 	/* Get current event names */
-	namelist = get_perf_event_names(fd, false);
-
-	for (j = 0; j < nr_probes; j++) {
-		pp = probes + j;
-		if (!pp->event)
-			pp->event = xstrdup(pp->function);
-		if (!pp->group)
-			pp->group = xstrdup(PERFPROBE_GROUP);
-		/* If force_add is true, suffix search is allowed */
-		allow_suffix = force_add;
-		for (i = 0; i < pp->found; i++) {
-			/* Get an unused new event name */
-			get_new_event_name(event, 64, pp->event, namelist,
-					   allow_suffix);
-			snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
-				 pp->retprobe ? 'r' : 'p',
-				 pp->group, event,
-				 pp->probes[i]);
-			write_trace_kprobe_event(fd, buf);
-			printf("Added new event:\n");
-			/* Get the first parameter (probe-point) */
-			sscanf(pp->probes[i], "%s", buf);
-			show_perf_probe_event(event, buf, pp);
-			/* Add added event name to namelist */
-			strlist__add(namelist, event);
-			/*
-			 * Probes after the first probe which comes from same
-			 * user input are always allowed to add suffix, because
-			 * there might be several addresses corresponding to
-			 * one code line.
-			 */
-			allow_suffix = true;
-		}
+	namelist = get_kprobe_trace_event_names(fd, false);
+
+	printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":");
+	for (i = 0; i < ntevs; i++) {
+		tev = &tevs[i];
+		if (pev->event)
+			event = pev->event;
+		else
+			if (pev->point.function)
+				event = pev->point.function;
+			else
+				event = tev->point.symbol;
+		if (pev->group)
+			group = pev->group;
+		else
+			group = PERFPROBE_GROUP;
+
+		/* Get an unused new event name */
+		get_new_event_name(buf, 64, event, namelist, allow_suffix);
+		event = buf;
+
+		tev->event = xstrdup(event);
+		tev->group = xstrdup(group);
+		write_kprobe_trace_event(fd, tev);
+		/* Add added event name to namelist */
+		strlist__add(namelist, event);
+
+		/* Trick here - save current event/group */
+		event = pev->event;
+		group = pev->group;
+		pev->event = tev->event;
+		pev->group = tev->group;
+		show_perf_probe_event(pev);
+		/* Trick here - restore current event/group */
+		pev->event = (char *)event;
+		pev->group = (char *)group;
+
+		/*
+		 * Probes after the first probe which comes from same
+		 * user input are always allowed to add suffix, because
+		 * there might be several addresses corresponding to
+		 * one code line.
+		 */
+		allow_suffix = true;
 	}
 	/* Show how to use the event. */
 	printf("\nYou can now use it on all perf tools, such as:\n\n");
-	printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
+	printf("\tperf record -e %s:%s -a sleep 1\n\n", tev->group, tev->event);
 
 	strlist__delete(namelist);
 	close(fd);
 }
 
-/* Currently just checking function name from symbol map */
-static void evaluate_probe_point(struct probe_point *pp)
+static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
+					  struct kprobe_trace_event **tevs)
 {
 	struct symbol *sym;
-	sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
-				       pp->function, NULL);
-	if (!sym)
-		die("Kernel symbol \'%s\' not found - probe not added.",
-		    pp->function);
-}
-
-void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
-			     bool force_add, bool need_dwarf)
-{
-	int i, ret;
-	struct probe_point *pp;
+	bool need_dwarf;
 #ifndef NO_DWARF_SUPPORT
 	int fd;
 #endif
-	/* Add probes */
-	init_vmlinux();
+	int ntevs = 0, i;
+	struct kprobe_trace_event *tev;
+
+	need_dwarf = perf_probe_event_need_dwarf(pev);
 
 	if (need_dwarf)
 #ifdef NO_DWARF_SUPPORT
@@ -721,57 +859,90 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
 	}
 
 	/* Searching probe points */
-	for (i = 0; i < nr_probes; i++) {
-		pp = &probes[i];
-		if (pp->found)
-			continue;
-
-		lseek(fd, SEEK_SET, 0);
-		ret = find_probe_point(fd, pp);
-		if (ret > 0)
-			continue;
-		if (ret == 0) {	/* No error but failed to find probe point. */
-			synthesize_perf_probe_point(pp);
-			die("Probe point '%s' not found. - probe not added.",
-			    pp->probes[0]);
-		}
-		/* Error path */
-		if (need_dwarf) {
-			if (ret == -ENOENT)
-				pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
-			die("Could not analyze debuginfo.");
-		}
-		pr_debug("An error occurred in debuginfo analysis."
-			 " Try to use symbols.\n");
-		break;
+	ntevs = find_kprobe_trace_events(fd, pev, tevs);
+
+	if (ntevs > 0)	/* Found */
+		goto found;
+
+	if (ntevs == 0)	/* No error but failed to find probe point. */
+		die("Probe point '%s' not found. - probe not added.",
+		    synthesize_perf_probe_point(&pev->point));
+
+	/* Error path */
+	if (need_dwarf) {
+		if (ntevs == -ENOENT)
+			pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
+		die("Could not analyze debuginfo.");
 	}
-	close(fd);
+	pr_debug("An error occurred in debuginfo analysis."
+		 " Try to use symbols.\n");
 
 end_dwarf:
 #endif /* !NO_DWARF_SUPPORT */
 
-	/* Synthesize probes without dwarf */
-	for (i = 0; i < nr_probes; i++) {
-		pp = &probes[i];
-		if (pp->found)	/* This probe is already found. */
-			continue;
+	/* Allocate trace event buffer */
+	ntevs = 1;
+	tev = *tevs = xzalloc(sizeof(struct kprobe_trace_event));
+
+	/* Copy parameters */
+	tev->point.symbol = xstrdup(pev->point.function);
+	tev->point.offset = pev->point.offset;
+	tev->nargs = pev->nargs;
+	if (tev->nargs) {
+		tev->args = xzalloc(sizeof(struct kprobe_trace_arg)
+				    * tev->nargs);
+		for (i = 0; i < tev->nargs; i++)
+			tev->args[i].value = xstrdup(pev->args[i].name);
+	}
+
+	/* Currently just checking function name from symbol map */
+	sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
+				       tev->point.symbol, NULL);
+	if (!sym)
+		die("Kernel symbol \'%s\' not found - probe not added.",
+		    tev->point.symbol);
+found:
+	close(fd);
+	return ntevs;
+}
+
+struct __event_package {
+	struct perf_probe_event		*pev;
+	struct kprobe_trace_event	*tevs;
+	int				ntevs;
+};
 
-		evaluate_probe_point(pp);
-		ret = synthesize_trace_kprobe_event(pp);
-		if (ret == -E2BIG)
-			die("probe point definition becomes too long.");
-		else if (ret < 0)
-			die("Failed to synthesize a probe point.");
+void add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
+			   bool force_add)
+{
+	int i;
+	struct __event_package *pkgs;
+
+	pkgs = xzalloc(sizeof(struct __event_package) * npevs);
+
+	/* Init vmlinux path */
+	init_vmlinux();
+
+	/* Loop 1: convert all events */
+	for (i = 0; i < npevs; i++) {
+		pkgs[i].pev = &pevs[i];
+		/* Convert with or without debuginfo */
+		pkgs[i].ntevs = convert_to_kprobe_trace_events(pkgs[i].pev,
+							       &pkgs[i].tevs);
 	}
 
-	/* Settng up probe points */
-	__add_trace_kprobe_events(probes, nr_probes, force_add);
+	/* Loop 2: add all events */
+	for (i = 0; i < npevs; i++)
+		__add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs,
+					  pkgs[i].ntevs, force_add);
+	/* TODO: cleanup all trace events? */
 }
 
 static void __del_trace_kprobe_event(int fd, struct str_node *ent)
 {
 	char *p;
 	char buf[128];
+	int ret;
 
 	/* Convert from perf-probe event to trace-kprobe event */
 	if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
@@ -781,7 +952,10 @@ static void __del_trace_kprobe_event(int fd, struct str_node *ent)
 		die("Internal error: %s should have ':' but not.", ent->s);
 	*p = '/';
 
-	write_trace_kprobe_event(fd, buf);
+	pr_debug("Writing event: %s\n", buf);
+	ret = write(fd, buf, strlen(buf));
+	if (ret <= 0)
+		die("Failed to write event: %s", strerror(errno));
 	printf("Remove event: %s\n", ent->s);
 }
 
@@ -814,7 +988,7 @@ static void del_trace_kprobe_event(int fd, const char *group,
 		pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
 }
 
-void del_trace_kprobe_events(struct strlist *dellist)
+void del_perf_probe_events(struct strlist *dellist)
 {
 	int fd;
 	const char *group, *event;
@@ -824,7 +998,7 @@ void del_trace_kprobe_events(struct strlist *dellist)
 
 	fd = open_kprobe_events(true);
 	/* Get current event names */
-	namelist = get_perf_event_names(fd, true);
+	namelist = get_kprobe_trace_event_names(fd, true);
 
 	strlist__for_each(ent, dellist) {
 		str = xstrdup(ent->s);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 703b887..2a2f0a2 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -2,24 +2,113 @@
 #define _PROBE_EVENT_H
 
 #include <stdbool.h>
-#include "probe-finder.h"
 #include "strlist.h"
 
 extern bool probe_event_dry_run;
 
-extern void parse_line_range_desc(const char *arg, struct line_range *lr);
-extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
-				   bool *need_dwarf);
-extern int synthesize_perf_probe_point(struct probe_point *pp);
-extern int synthesize_perf_probe_event(struct probe_point *pp);
-extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
-extern int synthesize_trace_kprobe_event(struct probe_point *pp);
-extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
-				    bool force_add, bool need_dwarf);
-extern void del_trace_kprobe_events(struct strlist *dellist);
+/* kprobe-tracer tracing point */
+struct kprobe_trace_point {
+	char		*symbol;	/* Base symbol */
+	unsigned long	offset;		/* Offset from symbol */
+	bool		retprobe;	/* Return probe flag */
+};
+
+/* kprobe-tracer tracing argument referencing offset */
+struct kprobe_trace_arg_ref {
+	struct kprobe_trace_arg_ref	*next;	/* Next reference */
+	long				offset;	/* Offset value */
+};
+
+/* kprobe-tracer tracing argument */
+struct kprobe_trace_arg {
+	char				*name;	/* Argument name */
+	char				*value;	/* Base value */
+	struct kprobe_trace_arg_ref	*ref;	/* Referencing offset */
+};
+
+/* kprobe-tracer tracing event (point + arg) */
+struct kprobe_trace_event {
+	char				*event;	/* Event name */
+	char				*group;	/* Group name */
+	struct kprobe_trace_point	point;	/* Trace point */
+	int				nargs;	/* Number of args */
+	struct kprobe_trace_arg		*args;	/* Arguments */
+};
+
+/* Perf probe probing point */
+struct perf_probe_point {
+	char		*file;		/* File path */
+	char		*function;	/* Function name */
+	int		line;		/* Line number */
+	char		*lazy_line;	/* Lazy matching pattern */
+	unsigned long	offset;		/* Offset from function entry */
+	bool		retprobe;	/* Return probe flag */
+};
+
+/* Perf probe probing argument */
+struct perf_probe_arg {
+	char		*name;		/* Argument name */
+};
+
+/* Perf probe probing event (point + arg) */
+struct perf_probe_event {
+	char			*event;	/* Event name */
+	char			*group;	/* Group name */
+	struct perf_probe_point	point;	/* Probe point */
+	int			nargs;	/* Number of arguments */
+	struct perf_probe_arg	*args;	/* Arguments */
+};
+
+
+/* Line number container */
+struct line_node {
+	struct list_head	list;
+	unsigned int		line;
+};
+
+/* Line range */
+struct line_range {
+	char			*file;		/* File name */
+	char			*function;	/* Function name */
+	unsigned int		start;		/* Start line number */
+	unsigned int		end;		/* End line number */
+	int			offset;		/* Start line offset */
+	char			*path;		/* Real path name */
+	struct list_head	line_list;	/* Visible lines */
+};
+
+/* Command string to events */
+extern void parse_perf_probe_command(const char *cmd,
+				     struct perf_probe_event *pev);
+extern void parse_kprobe_trace_command(const char *cmd,
+				       struct kprobe_trace_event *tev);
+
+/* Events to command string */
+extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
+extern char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev);
+
+/* Check the perf_probe_event needs debuginfo */
+extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
+
+/* Convert from kprobe_trace_event to perf_probe_event */
+extern void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
+					struct perf_probe_event *pev);
+
+/* Release event contents */
+extern void clear_perf_probe_event(struct perf_probe_event *pev);
+extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev);
+
+/* Command string to line-range */
+extern void parse_line_range_desc(const char *cmd, struct line_range *lr);
+
+
+extern void add_perf_probe_events(struct perf_probe_event *pevs, int ntevs,
+				  bool force_add);
+extern void del_perf_probe_events(struct strlist *dellist);
 extern void show_perf_probe_events(void);
 extern void show_line_range(struct line_range *lr);
 
+
 /* Maximum index number of event-name postfix */
 #define MAX_EVENT_INDEX	1024
 
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 3942e14..251b4c4 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -319,19 +319,20 @@ static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
  */
 
 /* Show a location */
-static void show_location(Dwarf_Op *op, struct probe_finder *pf)
+static void convert_location(Dwarf_Op *op, struct probe_finder *pf)
 {
 	unsigned int regn;
 	Dwarf_Word offs = 0;
-	int deref = 0, ret;
+	bool ref = false;
 	const char *regs;
+	struct kprobe_trace_arg *tvar = pf->tvar;
 
 	/* TODO: support CFA */
 	/* If this is based on frame buffer, set the offset */
 	if (op->atom == DW_OP_fbreg) {
 		if (pf->fb_ops == NULL)
 			die("The attribute of frame base is not supported.\n");
-		deref = 1;
+		ref = true;
 		offs = op->number;
 		op = &pf->fb_ops[0];
 	}
@@ -339,13 +340,13 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf)
 	if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
 		regn = op->atom - DW_OP_breg0;
 		offs += op->number;
-		deref = 1;
+		ref = true;
 	} else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
 		regn = op->atom - DW_OP_reg0;
 	} else if (op->atom == DW_OP_bregx) {
 		regn = op->number;
 		offs += op->number2;
-		deref = 1;
+		ref = true;
 	} else if (op->atom == DW_OP_regx) {
 		regn = op->number;
 	} else
@@ -355,17 +356,15 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf)
 	if (!regs)
 		die("%u exceeds max register number.", regn);
 
-	if (deref)
-		ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)",
-			       pf->var, (intmax_t)offs, regs);
-	else
-		ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
-	DIE_IF(ret < 0);
-	DIE_IF(ret >= pf->len);
+	tvar->value = xstrdup(regs);
+	if (ref) {
+		tvar->ref = xzalloc(sizeof(struct kprobe_trace_arg_ref));
+		tvar->ref->offset = (long)offs;
+	}
 }
 
 /* Show a variables in kprobe event format */
-static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
+static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 {
 	Dwarf_Attribute attr;
 	Dwarf_Op *expr;
@@ -379,50 +378,51 @@ static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 	if (ret <= 0 || nexpr == 0)
 		goto error;
 
-	show_location(expr, pf);
+	convert_location(expr, pf);
 	/* *expr will be cached in libdw. Don't free it. */
 	return ;
 error:
 	/* TODO: Support const_value */
 	die("Failed to find the location of %s at this address.\n"
-	    " Perhaps, it has been optimized out.", pf->var);
+	    " Perhaps, it has been optimized out.", pf->pvar->name);
 }
 
 /* Find a variable in a subprogram die */
 static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
-	int ret;
 	Dwarf_Die vr_die;
 
 	/* TODO: Support struct members and arrays */
-	if (!is_c_varname(pf->var)) {
-		/* Output raw parameters */
-		ret = snprintf(pf->buf, pf->len, " %s", pf->var);
-		DIE_IF(ret < 0);
-		DIE_IF(ret >= pf->len);
-		return ;
+	if (!is_c_varname(pf->pvar->name)) {
+		/* Copy raw parameters */
+		pf->tvar->value = xstrdup(pf->pvar->name);
+	} else {
+		pf->tvar->name = xstrdup(pf->pvar->name);
+		pr_debug("Searching '%s' variable in context.\n",
+			 pf->pvar->name);
+		/* Search child die for local variables and parameters. */
+		if (!die_find_variable(sp_die, pf->pvar->name, &vr_die))
+			die("Failed to find '%s' in this function.",
+			    pf->pvar->name);
+		convert_variable(&vr_die, pf);
 	}
-
-	pr_debug("Searching '%s' variable in context.\n", pf->var);
-	/* Search child die for local variables and parameters. */
-	if (!die_find_variable(sp_die, pf->var, &vr_die))
-		die("Failed to find '%s' in this function.", pf->var);
-
-	show_variable(&vr_die, pf);
 }
 
 /* Show a probe point to output buffer */
-static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
+static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
-	struct probe_point *pp = pf->pp;
+	struct kprobe_trace_event *tev;
 	Dwarf_Addr eaddr;
 	Dwarf_Die die_mem;
 	const char *name;
-	char tmp[MAX_PROBE_BUFFER];
-	int ret, i, len;
+	int ret, i;
 	Dwarf_Attribute fb_attr;
 	size_t nops;
 
+	if (pf->ntevs == MAX_PROBES)
+		die("Too many( > %d) probe point found.\n", MAX_PROBES);
+	tev = &pf->tevs[pf->ntevs++];
+
 	/* If no real subprogram, find a real one */
 	if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
 		sp_die = die_find_real_subprogram(&pf->cu_die,
@@ -431,31 +431,18 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 			die("Probe point is not found in subprograms.");
 	}
 
-	/* Output name of probe point */
+	/* Copy the name of probe point */
 	name = dwarf_diename(sp_die);
 	if (name) {
 		dwarf_entrypc(sp_die, &eaddr);
-		ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name,
-				(unsigned long)(pf->addr - eaddr));
-		/* Copy the function name if possible */
-		if (!pp->function) {
-			pp->function = xstrdup(name);
-			pp->offset = (size_t)(pf->addr - eaddr);
-		}
-	} else {
+		tev->point.symbol = xstrdup(name);
+		tev->point.offset = (unsigned long)(pf->addr - eaddr);
+	} else
 		/* This function has no name. */
-		ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx",
-			       (uintmax_t)pf->addr);
-		if (!pp->function) {
-			/* TODO: Use _stext */
-			pp->function = xstrdup("");
-			pp->offset = (size_t)pf->addr;
-		}
-	}
-	DIE_IF(ret < 0);
-	DIE_IF(ret >= MAX_PROBE_BUFFER);
-	len = ret;
-	pr_debug("Probe point found: %s\n", tmp);
+		tev->point.offset = (unsigned long)pf->addr;
+
+	pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
+		 tev->point.offset);
 
 	/* Get the frame base attribute/ops */
 	dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
@@ -465,22 +452,16 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 
 	/* Find each argument */
 	/* TODO: use dwarf_cfi_addrframe */
-	for (i = 0; i < pp->nr_args; i++) {
-		pf->var = pp->args[i];
-		pf->buf = &tmp[len];
-		pf->len = MAX_PROBE_BUFFER - len;
+	tev->nargs = pf->pev->nargs;
+	tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
+	for (i = 0; i < pf->pev->nargs; i++) {
+		pf->pvar = &pf->pev->args[i];
+		pf->tvar = &tev->args[i];
 		find_variable(sp_die, pf);
-		len += strlen(pf->buf);
 	}
 
 	/* *pf->fb_ops will be cached in libdw. Don't free it. */
 	pf->fb_ops = NULL;
-
-	if (pp->found == MAX_PROBES)
-		die("Too many( > %d) probe point found.\n", MAX_PROBES);
-
-	pp->probes[pp->found] = xstrdup(tmp);
-	pp->found++;
 }
 
 /* Find probe point from its line number */
@@ -512,7 +493,7 @@ static void find_probe_point_by_line(struct probe_finder *pf)
 			 (int)i, lineno, (uintmax_t)addr);
 		pf->addr = addr;
 
-		show_probe_point(NULL, pf);
+		convert_probe_point(NULL, pf);
 		/* Continuing, because target line might be inlined. */
 	}
 }
@@ -563,7 +544,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 	if (list_empty(&pf->lcache)) {
 		/* Matching lazy line pattern */
 		ret = find_lazy_match_lines(&pf->lcache, pf->fname,
-					    pf->pp->lazy_line);
+					    pf->pev->point.lazy_line);
 		if (ret <= 0)
 			die("No matched lines found in %s.", pf->fname);
 	}
@@ -596,7 +577,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 			 (int)i, lineno, (unsigned long long)addr);
 		pf->addr = addr;
 
-		show_probe_point(sp_die, pf);
+		convert_probe_point(sp_die, pf);
 		/* Continuing, because target line might be inlined. */
 	}
 	/* TODO: deallocate lines, but how? */
@@ -605,7 +586,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
 {
 	struct probe_finder *pf = (struct probe_finder *)data;
-	struct probe_point *pp = pf->pp;
+	struct perf_probe_point *pp = &pf->pev->point;
 
 	if (pp->lazy_line)
 		find_probe_point_lazy(in_die, pf);
@@ -616,7 +597,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
 		pr_debug("found inline addr: 0x%jx\n",
 			 (uintmax_t)pf->addr);
 
-		show_probe_point(in_die, pf);
+		convert_probe_point(in_die, pf);
 	}
 
 	return DWARF_CB_OK;
@@ -626,7 +607,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
 static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
 {
 	struct probe_finder *pf = (struct probe_finder *)data;
-	struct probe_point *pp = pf->pp;
+	struct perf_probe_point *pp = &pf->pev->point;
 
 	/* Check tag and diename */
 	if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
@@ -646,7 +627,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
 			pf->addr = die_get_entrypc(sp_die);
 			pf->addr += pp->offset;
 			/* TODO: Check the address in this function */
-			show_probe_point(sp_die, pf);
+			convert_probe_point(sp_die, pf);
 		}
 	} else
 		/* Inlined function: search instances */
@@ -660,20 +641,25 @@ static void find_probe_point_by_func(struct probe_finder *pf)
 	dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
 }
 
-/* Find a probe point */
-int find_probe_point(int fd, struct probe_point *pp)
+/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
+int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
+			     struct kprobe_trace_event **tevs)
 {
-	struct probe_finder pf = {.pp = pp};
+	struct probe_finder pf = {.pev = pev};
+	struct perf_probe_point *pp = &pev->point;
 	Dwarf_Off off, noff;
 	size_t cuhl;
 	Dwarf_Die *diep;
 	Dwarf *dbg;
 
+	pf.tevs = xzalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES);
+	*tevs = pf.tevs;
+	pf.ntevs = 0;
+
 	dbg = dwarf_begin(fd, DWARF_C_READ);
 	if (!dbg)
 		return -ENOENT;
 
-	pp->found = 0;
 	off = 0;
 	line_list__init(&pf.lcache);
 	/* Loop on CUs (Compilation Unit) */
@@ -704,7 +690,7 @@ int find_probe_point(int fd, struct probe_point *pp)
 	line_list__free(&pf.lcache);
 	dwarf_end(dbg);
 
-	return pp->found;
+	return pf.ntevs;
 }
 
 /* Find line range from its line number */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 21f7354..4949526 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include "util.h"
+#include "probe-event.h"
 
 #define MAX_PATH_LEN		 256
 #define MAX_PROBE_BUFFER	1024
@@ -14,67 +15,32 @@ static inline int is_c_varname(const char *name)
 	return isalpha(name[0]) || name[0] == '_';
 }
 
-struct probe_point {
-	char			*event;			/* Event name */
-	char			*group;			/* Event group */
-
-	/* Inputs */
-	char			*file;			/* File name */
-	int			line;			/* Line number */
-	char			*lazy_line;		/* Lazy line pattern */
-
-	char			*function;		/* Function name */
-	int			offset;			/* Offset bytes */
-
-	int			nr_args;		/* Number of arguments */
-	char			**args;			/* Arguments */
-
-	int			retprobe;		/* Return probe */
-
-	/* Output */
-	int			found;			/* Number of found probe points */
-	char			*probes[MAX_PROBES];	/* Output buffers (will be allocated)*/
-};
-
-/* Line number container */
-struct line_node {
-	struct list_head	list;
-	unsigned int		line;
-};
-
-/* Line range */
-struct line_range {
-	char			*file;			/* File name */
-	char			*function;		/* Function name */
-	unsigned int		start;			/* Start line number */
-	unsigned int		end;			/* End line number */
-	int			offset;			/* Start line offset */
-	char			*path;			/* Real path name */
-	struct list_head	line_list;		/* Visible lines */
-};
-
 #ifndef NO_DWARF_SUPPORT
-extern int find_probe_point(int fd, struct probe_point *pp);
+/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
+extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
+				    struct kprobe_trace_event **tevs);
+
 extern int find_line_range(int fd, struct line_range *lr);
 
 #include <dwarf.h>
 #include <libdw.h>
 
 struct probe_finder {
-	struct probe_point	*pp;		/* Target probe point */
+	struct perf_probe_event	*pev;		/* Target probe event */
+	int			ntevs;		/* number of trace events */
+	struct kprobe_trace_event *tevs;	/* Result trace events */
 
 	/* For function searching */
 	Dwarf_Addr		addr;		/* Address */
-	const char		*fname;		/* File name */
+	const char		*fname;		/* Real file name */
 	int			lno;		/* Line number */
 	Dwarf_Die		cu_die;		/* Current CU */
+	struct list_head	lcache;		/* Line cache for lazy match */
 
 	/* For variable searching */
 	Dwarf_Op		*fb_ops;	/* Frame base attribute */
-	const char		*var;		/* Current variable name */
-	char			*buf;		/* Current output buffer */
-	int			len;		/* Length of output buffer */
-	struct list_head	lcache;		/* Line cache for lazy match */
+	struct perf_probe_arg	*pvar;		/* Current target variable */
+	struct kprobe_trace_arg	*tvar;		/* Current result variable */
 };
 
 struct line_finder {


-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* [PATCH -tip 09/10] perf probe: List probes with line number and file name
  2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
                   ` (7 preceding siblings ...)
  2010-03-16 22:06 ` [PATCH -tip 08/10] perf probe: Introduce kprobe_trace_event and perf_probe_event Masami Hiramatsu
@ 2010-03-16 22:06 ` Masami Hiramatsu
  2010-03-17 11:29   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2010-03-16 22:06 ` [PATCH -tip 10/10] perf probe: Accessing members in data structures Masami Hiramatsu
  2010-03-17 10:34 ` [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Ingo Molnar
  10 siblings, 1 reply; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-16 22:06 UTC (permalink / raw)
  To: Ingo Molnar, lkml
  Cc: systemtap, DLE, Masami Hiramatsu, Ingo Molnar,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Paul Mackerras,
	Mike Galbraith, Peter Zijlstra

Improve --list to show current exist probes with line number and file name.
This enables user easily to check which line is already probed.

e.g.
 ./perf probe --list
 probe:vfs_read       (on vfs_read:8@linux-2.6-tip/fs/read_write.c)

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
---

 tools/perf/util/probe-event.c  |   55 ++++++++++++++++++++++++-------
 tools/perf/util/probe-finder.c |   70 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/probe-finder.h |    4 ++
 3 files changed, 116 insertions(+), 13 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index b44ddfb..4e3c1ae 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -70,7 +70,6 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 	return ret;
 }
 
-
 static struct map_groups kmap_groups;
 static struct map *kmaps[MAP__NR_TYPES];
 
@@ -357,27 +356,39 @@ void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
 /* Compose only probe point (not argument) */
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 {
-	char *buf;
-	char offs[64] = "", line[64] = "";
-	int ret;
+	char *buf, *tmp;
+	char offs[32] = "", line[32] = "", file[32] = "";
+	int ret, len;
 
 	buf = xzalloc(MAX_CMDLEN);
 	if (pp->offset) {
-		ret = e_snprintf(offs, 64, "+%lu", pp->offset);
+		ret = e_snprintf(offs, 32, "+%lu", pp->offset);
 		if (ret <= 0)
 			goto error;
 	}
 	if (pp->line) {
-		ret = e_snprintf(line, 64, ":%d", pp->line);
+		ret = e_snprintf(line, 32, ":%d", pp->line);
+		if (ret <= 0)
+			goto error;
+	}
+	if (pp->file) {
+		len = strlen(pp->file) - 32;
+		if (len < 0)
+			len = 0;
+		tmp = strchr(pp->file + len, '/');
+		if (!tmp)
+			tmp = pp->file + len - 1;
+		ret = e_snprintf(file, 32, "@%s", tmp + 1);
 		if (ret <= 0)
 			goto error;
 	}
 
 	if (pp->function)
-		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
-				 offs, pp->retprobe ? "%return" : "", line);
+		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
+				 offs, pp->retprobe ? "%return" : "", line,
+				 file);
 	else
-		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
+		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
 	if (ret <= 0)
 		goto error;
 
@@ -511,15 +522,32 @@ void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
 {
 	char buf[64];
 	int i;
+#ifndef NO_DWARF_SUPPORT
+	struct symbol *sym;
+	int fd, ret = 0;
 
-	pev->event = xstrdup(tev->event);
-	pev->group = xstrdup(tev->group);
-
+	sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
+				       tev->point.symbol, NULL);
+	if (sym) {
+		fd = open_vmlinux();
+		ret = find_perf_probe_point(fd, sym->start + tev->point.offset,
+					    &pev->point);
+		close(fd);
+	}
+	if (ret <= 0) {
+		pev->point.function = xstrdup(tev->point.symbol);
+		pev->point.offset = tev->point.offset;
+	}
+#else
 	/* Convert trace_point to probe_point */
 	pev->point.function = xstrdup(tev->point.symbol);
 	pev->point.offset = tev->point.offset;
+#endif
 	pev->point.retprobe = tev->point.retprobe;
 
+	pev->event = xstrdup(tev->event);
+	pev->group = xstrdup(tev->group);
+
 	/* Convert trace_arg to probe_arg */
 	pev->nargs = tev->nargs;
 	pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
@@ -650,7 +678,7 @@ static void show_perf_probe_event(struct perf_probe_event *pev)
 	ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
 	if (ret < 0)
 		die("Failed to copy event: %s", strerror(-ret));
-	printf("  %-40s (on %s", buf, place);
+	printf("  %-20s (on %s", buf, place);
 
 	if (pev->nargs > 0) {
 		printf(" with");
@@ -671,6 +699,7 @@ void show_perf_probe_events(void)
 	struct str_node *ent;
 
 	setup_pager();
+	init_vmlinux();
 
 	memset(&tev, 0, sizeof(tev));
 	memset(&pev, 0, sizeof(pev));
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 251b4c4..e02b607 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -693,6 +693,76 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
 	return pf.ntevs;
 }
 
+/* Reverse search */
+int find_perf_probe_point(int fd, unsigned long addr,
+			  struct perf_probe_point *ppt)
+{
+	Dwarf_Die cudie, spdie, indie;
+	Dwarf *dbg;
+	Dwarf_Line *line;
+	Dwarf_Addr laddr, eaddr;
+	const char *tmp;
+	int lineno, ret = 0;
+
+	dbg = dwarf_begin(fd, DWARF_C_READ);
+	if (!dbg)
+		return -ENOENT;
+
+	/* Find cu die */
+	if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie))
+		return -EINVAL;
+
+	/* Find a corresponding line */
+	line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
+	if (line) {
+		dwarf_lineaddr(line, &laddr);
+		if ((Dwarf_Addr)addr == laddr) {
+			dwarf_lineno(line, &lineno);
+			ppt->line = lineno;
+
+			tmp = dwarf_linesrc(line, NULL, NULL);
+			DIE_IF(!tmp);
+			ppt->file = xstrdup(tmp);
+			ret = 1;
+		}
+	}
+
+	/* Find a corresponding function */
+	if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
+		tmp = dwarf_diename(&spdie);
+		if (!tmp)
+			goto end;
+
+		dwarf_entrypc(&spdie, &eaddr);
+		if (!lineno) {
+			/* We don't have a line number, let's use offset */
+			ppt->function = xstrdup(tmp);
+			ppt->offset = addr - (unsigned long)eaddr;
+			ret = 1;
+			goto end;
+		}
+		if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, &indie)) {
+			/* addr in an inline function */
+			tmp = dwarf_diename(&indie);
+			if (!tmp)
+				goto end;
+			dwarf_decl_line(&indie, &lineno);
+		} else {
+			if (eaddr == addr)	/* No offset: function entry */
+				lineno = ppt->line;
+			else
+				dwarf_decl_line(&spdie, &lineno);
+		}
+		ppt->function = xstrdup(tmp);
+		ppt->line -= lineno;	/* Make a relative line number */
+	}
+
+end:
+	dwarf_end(dbg);
+	return ret;
+}
+
+
 /* Find line range from its line number */
 static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 {
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 4949526..2f2307d 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -20,6 +20,10 @@ static inline int is_c_varname(const char *name)
 extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
 				    struct kprobe_trace_event **tevs);
 
+/* Find a perf_probe_point from debuginfo */
+extern int find_perf_probe_point(int fd, unsigned long addr,
+				 struct perf_probe_point *ppt);
+
 extern int find_line_range(int fd, struct line_range *lr);
 
 #include <dwarf.h>


-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* [PATCH -tip 10/10] perf probe: Accessing members in data structures
  2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
                   ` (8 preceding siblings ...)
  2010-03-16 22:06 ` [PATCH -tip 09/10] perf probe: List probes with line number and file name Masami Hiramatsu
@ 2010-03-16 22:06 ` Masami Hiramatsu
  2010-03-17 10:25   ` Mark Wielaard
  2010-03-17 11:30   ` [tip:perf/core] perf probe: Add data structure member access support tip-bot for Masami Hiramatsu
  2010-03-17 10:34 ` [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Ingo Molnar
  10 siblings, 2 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-16 22:06 UTC (permalink / raw)
  To: Ingo Molnar, lkml
  Cc: systemtap, DLE, Masami Hiramatsu, Ingo Molnar,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Paul Mackerras,
	Mike Galbraith, Peter Zijlstra

Support accessing members in the data structures. With this,
perf-probe accepts data-structure members(IOW, it now accepts
dot '.' and arrow '->' operators) as probe arguemnts.

e.g.

 ./perf probe --add 'schedule:44 rq->curr'

 ./perf probe --add 'vfs_read file->f_op->read file->f_path.dentry'

Note that '>' can be interpreted as redirection in command-line.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
---

 tools/perf/util/probe-event.c  |   90 +++++++++++++++++++++++++++++++++-
 tools/perf/util/probe-event.h  |   12 ++++-
 tools/perf/util/probe-finder.c |  105 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 201 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 4e3c1ae..64dea6c 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -262,6 +262,49 @@ static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 		 pp->lazy_line);
 }
 
+/* Parse perf-probe event argument */
+static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg)
+{
+	const char *tmp;
+	struct perf_probe_arg_field **fieldp;
+
+	pr_debug("parsing arg: %s into ", str);
+
+	tmp = strpbrk(str, "-.");
+	if (!is_c_varname(str) || !tmp) {
+		/* A variable, register, symbol or special value */
+		arg->name = xstrdup(str);
+		pr_debug("%s\n", arg->name);
+		return;
+	}
+
+	/* Structure fields */
+	arg->name = xstrndup(str, tmp - str);
+	pr_debug("%s, ", arg->name);
+	fieldp = &arg->field;
+
+	do {
+		*fieldp = xzalloc(sizeof(struct perf_probe_arg_field));
+		if (*tmp == '.') {
+			str = tmp + 1;
+			(*fieldp)->ref = false;
+		} else if (tmp[1] == '>') {
+			str = tmp + 2;
+			(*fieldp)->ref = true;
+		} else
+			semantic_error("Argument parse error: %s", str);
+
+		tmp = strpbrk(str, "-.");
+		if (tmp) {
+			(*fieldp)->name = xstrndup(str, tmp - str);
+			pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
+			fieldp = &(*fieldp)->next;
+		}
+	} while (tmp);
+	(*fieldp)->name = xstrdup(str);
+	pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
+}
+
 /* Parse perf-probe event command */
 void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
 {
@@ -281,7 +324,7 @@ void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
 	pev->nargs = argc - 1;
 	pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
 	for (i = 0; i < pev->nargs; i++) {
-		pev->args[i].name = xstrdup(argv[i + 1]);
+		parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
 		if (is_c_varname(pev->args[i].name) && pev->point.retprobe)
 			semantic_error("You can't specify local variable for"
 				       " kretprobe");
@@ -353,6 +396,33 @@ void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
 	argv_free(argv);
 }
 
+/* Compose only probe arg */
+int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
+{
+	struct perf_probe_arg_field *field = pa->field;
+	int ret;
+	char *tmp = buf;
+
+	ret = e_snprintf(tmp, len, "%s", pa->name);
+	if (ret <= 0)
+		goto error;
+	tmp += ret;
+	len -= ret;
+
+	while (field) {
+		ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".",
+				 field->name);
+		if (ret <= 0)
+			goto error;
+		tmp += ret;
+		len -= ret;
+		field = field->next;
+	}
+	return tmp - buf;
+error:
+	die("Failed to synthesize perf probe argument: %s", strerror(-ret));
+}
+
 /* Compose only probe point (not argument) */
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 {
@@ -563,6 +633,7 @@ void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
 void clear_perf_probe_event(struct perf_probe_event *pev)
 {
 	struct perf_probe_point *pp = &pev->point;
+	struct perf_probe_arg_field *field, *next;
 	int i;
 
 	if (pev->event)
@@ -575,9 +646,18 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
 		free(pp->function);
 	if (pp->lazy_line)
 		free(pp->lazy_line);
-	for (i = 0; i < pev->nargs; i++)
+	for (i = 0; i < pev->nargs; i++) {
 		if (pev->args[i].name)
 			free(pev->args[i].name);
+		field = pev->args[i].field;
+		while (field) {
+			next = field->next;
+			if (field->name)
+				free(field->name);
+			free(field);
+			field = next;
+		}
+	}
 	if (pev->args)
 		free(pev->args);
 	memset(pev, 0, sizeof(*pev));
@@ -682,8 +762,10 @@ static void show_perf_probe_event(struct perf_probe_event *pev)
 
 	if (pev->nargs > 0) {
 		printf(" with");
-		for (i = 0; i < pev->nargs; i++)
-			printf(" %s", pev->args[i].name);
+		for (i = 0; i < pev->nargs; i++) {
+			synthesize_perf_probe_arg(&pev->args[i], buf, 128);
+			printf(" %s", buf);
+		}
 	}
 	printf(")\n");
 	free(place);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 2a2f0a2..cd308b0 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -45,9 +45,17 @@ struct perf_probe_point {
 	bool		retprobe;	/* Return probe flag */
 };
 
+/* Perf probe probing argument field chain */
+struct perf_probe_arg_field {
+	struct perf_probe_arg_field	*next;	/* Next field */
+	char				*name;	/* Name of the field */
+	bool				ref;	/* Referencing flag */
+};
+
 /* Perf probe probing argument */
 struct perf_probe_arg {
-	char		*name;		/* Argument name */
+	char				*name;	/* Argument name */
+	struct perf_probe_arg_field	*field;	/* Structure fields */
 };
 
 /* Perf probe probing event (point + arg) */
@@ -86,6 +94,8 @@ extern void parse_kprobe_trace_command(const char *cmd,
 /* Events to command string */
 extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
 extern char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev);
+extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf,
+				     size_t len);
 
 /* Check the perf_probe_event needs debuginfo */
 extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index e02b607..db52ec2 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -206,6 +206,28 @@ static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
 	return epc;
 }
 
+/* Get type die, but skip qualifiers and typedef */
+static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+{
+	Dwarf_Attribute attr;
+	int tag;
+
+	do {
+		if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL ||
+		    dwarf_formref_die(&attr, die_mem) == NULL)
+			return NULL;
+
+		tag = dwarf_tag(die_mem);
+		vr_die = die_mem;
+	} while (tag == DW_TAG_const_type ||
+		 tag == DW_TAG_restrict_type ||
+		 tag == DW_TAG_volatile_type ||
+		 tag == DW_TAG_shared_type ||
+		 tag == DW_TAG_typedef);
+
+	return die_mem;
+}
+
 /* Return values for die_find callbacks */
 enum {
 	DIE_FIND_CB_FOUND = 0,		/* End of Search */
@@ -314,6 +336,25 @@ static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
 			      die_mem);
 }
 
+static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
+{
+	const char *name = data;
+
+	if ((dwarf_tag(die_mem) == DW_TAG_member) &&
+	    (die_compare_name(die_mem, name) == 0))
+		return DIE_FIND_CB_FOUND;
+
+	return DIE_FIND_CB_SIBLING;
+}
+
+/* Find a member called 'name' */
+static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
+				  Dwarf_Die *die_mem)
+{
+	return die_find_child(st_die, __die_find_member_cb, (void *)name,
+			      die_mem);
+}
+
 /*
  * Probe finder related functions
  */
@@ -363,6 +404,62 @@ static void convert_location(Dwarf_Op *op, struct probe_finder *pf)
 	}
 }
 
+static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
+				    struct perf_probe_arg_field *field,
+				    struct kprobe_trace_arg_ref **ref_ptr)
+{
+	struct kprobe_trace_arg_ref *ref = *ref_ptr;
+	Dwarf_Attribute attr;
+	Dwarf_Die member;
+	Dwarf_Die type;
+	Dwarf_Word offs;
+
+	pr_debug("converting %s in %s\n", field->name, varname);
+	if (die_get_real_type(vr_die, &type) == NULL)
+		die("Failed to get a type information of %s.", varname);
+
+	/* Check the pointer and dereference */
+	if (dwarf_tag(&type) == DW_TAG_pointer_type) {
+		if (!field->ref)
+			die("Semantic error: %s must be referred by '->'",
+			    field->name);
+		/* Get the type pointed by this pointer */
+		if (die_get_real_type(&type, &type) == NULL)
+			die("Failed to get a type information of %s.", varname);
+
+		ref = xzalloc(sizeof(struct kprobe_trace_arg_ref));
+		if (*ref_ptr)
+			(*ref_ptr)->next = ref;
+		else
+			*ref_ptr = ref;
+	} else {
+		if (field->ref)
+			die("Semantic error: %s must be referred by '.'",
+			    field->name);
+		if (!ref)
+			die("Structure on a register is not supported yet.");
+	}
+
+	/* Verify it is a data structure  */
+	if (dwarf_tag(&type) != DW_TAG_structure_type)
+		die("%s is not a data structure.", varname);
+
+	if (die_find_member(&type, field->name, &member) == NULL)
+		die("%s(tyep:%s) has no member %s.", varname,
+		    dwarf_diename(&type), field->name);
+
+	/* Get the offset of the field */
+	if (dwarf_attr(&member, DW_AT_data_member_location, &attr) == NULL ||
+	    dwarf_formudata(&attr, &offs) != 0)
+		die("Failed to get the offset of %s.", field->name);
+	ref->offset += (long)offs;
+
+	/* Converting next field */
+	if (field->next)
+		convert_variable_fields(&member, field->name, field->next,
+					&ref);
+}
+
 /* Show a variables in kprobe event format */
 static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 {
@@ -379,6 +476,10 @@ static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 		goto error;
 
 	convert_location(expr, pf);
+
+	if (pf->pvar->field)
+		convert_variable_fields(vr_die, pf->pvar->name,
+					pf->pvar->field, &pf->tvar->ref);
 	/* *expr will be cached in libdw. Don't free it. */
 	return ;
 error:
@@ -391,13 +492,15 @@ error:
 static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
 	Dwarf_Die vr_die;
+	char buf[128];
 
 	/* TODO: Support struct members and arrays */
 	if (!is_c_varname(pf->pvar->name)) {
 		/* Copy raw parameters */
 		pf->tvar->value = xstrdup(pf->pvar->name);
 	} else {
-		pf->tvar->name = xstrdup(pf->pvar->name);
+		synthesize_perf_probe_arg(pf->pvar, buf, 128);
+		pf->tvar->name = xstrdup(buf);
 		pr_debug("Searching '%s' variable in context.\n",
 			 pf->pvar->name);
 		/* Search child die for local variables and parameters. */


-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* Re: [PATCH -tip 10/10] perf probe: Accessing members in data structures
  2010-03-16 22:06 ` [PATCH -tip 10/10] perf probe: Accessing members in data structures Masami Hiramatsu
@ 2010-03-17 10:25   ` Mark Wielaard
  2010-03-17 19:14     ` Masami Hiramatsu
  2010-03-17 11:30   ` [tip:perf/core] perf probe: Add data structure member access support tip-bot for Masami Hiramatsu
  1 sibling, 1 reply; 32+ messages in thread
From: Mark Wielaard @ 2010-03-17 10:25 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, lkml, systemtap, DLE, Frederic Weisbecker,
	Arnaldo Carvalho de Melo, Paul Mackerras, Mike Galbraith,
	Peter Zijlstra

On Tue, 2010-03-16 at 18:06 -0400, Masami Hiramatsu wrote:
> Support accessing members in the data structures. With this,
> perf-probe accepts data-structure members(IOW, it now accepts
> dot '.' and arrow '->' operators) as probe arguemnts.
> 
> e.g.
> 
>  ./perf probe --add 'schedule:44 rq->curr'
> 
>  ./perf probe --add 'vfs_read file->f_op->read file->f_path.dentry'
> 
> Note that '>' can be interpreted as redirection in command-line.

If you find that a problem then you can do like SystemTap does and allow
'.' in place of '->'. In the code you already use the
perf_probe_arg_field ref flag only to check that the DIE gives you the
same information. So you could just drop that and use any separator.
Then you decide based on whether you see a DW_TAG_pointer_type. This
gives the user some extra flexibility by letting them not having to care
about specifying extra type information already available elsewhere.

Cheers,

Mark


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

* Re: [PATCH -tip 00/10] perf-probe updates - data-structure support, etc.
  2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
                   ` (9 preceding siblings ...)
  2010-03-16 22:06 ` [PATCH -tip 10/10] perf probe: Accessing members in data structures Masami Hiramatsu
@ 2010-03-17 10:34 ` Ingo Molnar
  10 siblings, 0 replies; 32+ messages in thread
From: Ingo Molnar @ 2010-03-17 10:34 UTC (permalink / raw)
  To: Masami Hiramatsu; +Cc: lkml, systemtap, DLE


* Masami Hiramatsu <mhiramat@redhat.com> wrote:

> Hi Ingo,
> 
> Here are several updates of perf-probe.
> This updates includes data structure accessing support
> --list option enhancement and --dry-run option support.
> 
> - --dry-run allows users to run perf-probe just for checking
>   that the command works correctly.
> 
> - --list option enhancement allows user to check where the
>   probes are put on (with filename/line number).
> 
> - data structure accessing support allows user to trace
>   the contents of local variables/function parameters.

Very nice! I think tracing a data structure value at a given point in the 
source will be a rather popular feature.

> Long-term TODOs (future features):
>   - Enhance probe-finder to decode call frame instructions.
>   - Support tracing static variables (non global)
>   - Support variable basic types from debuginfo (e.g. char, int, ...)
>   - Support array element (var[N])
>   - Support string/dynamic arrays (*var, var[N..M])
>   - Support the type of return value
>   - Support force type-casting ((type)var)
>   - Support sys_perf_counter_open (for non-root users)
>   - Support dynamic array-indexing (var[var2])
> 
> Miscs:
>   - Better support for probes on modules
>   - More debugger like enhancements(%next, --disasm, etc.)

Sounds good :-)

> Masami Hiramatsu (10):
>       perf probe: Accessing members in data structures
>       perf probe: List probes with line number and file name
>       perf probe: Introduce kprobe_trace_event and perf_probe_event
>       perf probe: Add --dry-run option
>       perf probe: Introduce die_find_child() function
>       perf probe: Rename some die_get_* functions
>       perf probe: Rename session to param
>       perf probe: Move add-probe routine under util/
>       perf probe: Use wrapper functions
>       perf tools: Introduce xzalloc() for detecting out of memory
> 
> 
>  tools/perf/Documentation/perf-probe.txt |    5 
>  tools/perf/builtin-probe.c              |  191 +------
>  tools/perf/util/probe-event.c           |  830 +++++++++++++++++++++++--------
>  tools/perf/util/probe-event.h           |  123 ++++-
>  tools/perf/util/probe-finder.c          |  459 ++++++++++++-----
>  tools/perf/util/probe-finder.h          |   60 +-
>  tools/perf/util/util.h                  |    7 
>  7 files changed, 1115 insertions(+), 560 deletions(-)

Applied, thanks!

	Ingo

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

* [tip:perf/core] perf tools: Introduce xzalloc() for detecting out of memory conditions
  2010-03-16 22:05 ` [PATCH -tip 01/10] perf tools: Introduce xzalloc() for detecting out of memory Masami Hiramatsu
@ 2010-03-17 11:27   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-03-17 11:27 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, paulus, acme, hpa, mingo, a.p.zijlstra, efault,
	dle-develop, fweisbec, tglx, mhiramat, mingo, systemtap

Commit-ID:  a1d37d5285bcda07f9c0b80a2634ca20ab545297
Gitweb:     http://git.kernel.org/tip/a1d37d5285bcda07f9c0b80a2634ca20ab545297
Author:     Masami Hiramatsu <mhiramat@redhat.com>
AuthorDate: Tue, 16 Mar 2010 18:05:21 -0400
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Wed, 17 Mar 2010 11:32:29 +0100

perf tools: Introduce xzalloc() for detecting out of memory conditions

Introducing xzalloc() which wrapping zalloc() for detecting out
of memory conditions.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220521.32050.85155.stgit@localhost6.localdomain6>
[ -v2: small cleanups in surrounding code ]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 tools/perf/util/util.h |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 0f5b2a6..5270108 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -295,6 +295,13 @@ extern void *xmemdupz(const void *data, size_t len);
 extern char *xstrndup(const char *str, size_t len);
 extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
 
+static inline void *xzalloc(size_t size)
+{
+	void *buf = xmalloc(size);
+
+	return memset(buf, 0, size);
+}
+
 static inline void *zalloc(size_t size)
 {
 	return calloc(1, size);
@@ -309,6 +316,7 @@ static inline int has_extension(const char *filename, const char *ext)
 {
 	size_t len = strlen(filename);
 	size_t extlen = strlen(ext);
+
 	return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
 }
 
@@ -322,6 +330,7 @@ static inline int has_extension(const char *filename, const char *ext)
 #undef isalnum
 #undef tolower
 #undef toupper
+
 extern unsigned char sane_ctype[256];
 #define GIT_SPACE		0x01
 #define GIT_DIGIT		0x02

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

* [tip:perf/core] perf probe: Use wrapper functions
  2010-03-16 22:05 ` [PATCH -tip 02/10] perf probe: Use wrapper functions Masami Hiramatsu
@ 2010-03-17 11:27   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-03-17 11:27 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, paulus, acme, hpa, mingo, a.p.zijlstra, efault,
	dle-develop, fweisbec, tglx, mhiramat, mingo, systemtap

Commit-ID:  31facc5f1ac674fbcc29f212377e589396bb934c
Gitweb:     http://git.kernel.org/tip/31facc5f1ac674fbcc29f212377e589396bb934c
Author:     Masami Hiramatsu <mhiramat@redhat.com>
AuthorDate: Tue, 16 Mar 2010 18:05:30 -0400
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Wed, 17 Mar 2010 11:32:29 +0100

perf probe: Use wrapper functions

Use wrapped functions as much as possible, to check out of
memory conditions in perf probe.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220530.32050.53951.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 tools/perf/builtin-probe.c     |    4 +--
 tools/perf/util/probe-event.c  |   46 ++++++++++++++-------------------------
 tools/perf/util/probe-finder.c |   14 +++++-------
 3 files changed, 24 insertions(+), 40 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 152d6c9..b6afe7b 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -87,9 +87,7 @@ static void parse_probe_event_argv(int argc, const char **argv)
 	len = 0;
 	for (i = 0; i < argc; i++)
 		len += strlen(argv[i]) + 1;
-	buf = zalloc(len + 1);
-	if (!buf)
-		die("Failed to allocate memory for binding arguments.");
+	buf = xzalloc(len + 1);
 	len = 0;
 	for (i = 0; i < argc; i++)
 		len += sprintf(&buf[len], "%s ", argv[i]);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 7c004b6..88a3b6d 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -33,6 +33,7 @@
 #include <limits.h>
 
 #undef _GNU_SOURCE
+#include "util.h"
 #include "event.h"
 #include "string.h"
 #include "strlist.h"
@@ -90,9 +91,9 @@ void parse_line_range_desc(const char *arg, struct line_range *lr)
 		if (*tmp != '\0')
 			semantic_error("Tailing with invalid character '%d'.",
 				       *tmp);
-		tmp = strndup(arg, (ptr - arg));
+		tmp = xstrndup(arg, (ptr - arg));
 	} else
-		tmp = strdup(arg);
+		tmp = xstrdup(arg);
 
 	if (strchr(tmp, '.'))
 		lr->file = tmp;
@@ -135,7 +136,7 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 		if (!check_event_name(arg))
 			semantic_error("%s is bad for event name -it must "
 				       "follow C symbol-naming rule.", arg);
-		pp->event = strdup(arg);
+		pp->event = xstrdup(arg);
 		arg = tmp;
 	}
 
@@ -147,17 +148,16 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 
 	/* Check arg is function or file and copy it */
 	if (strchr(arg, '.'))	/* File */
-		pp->file = strdup(arg);
+		pp->file = xstrdup(arg);
 	else			/* Function */
-		pp->function = strdup(arg);
-	DIE_IF(pp->file == NULL && pp->function == NULL);
+		pp->function = xstrdup(arg);
 
 	/* Parse other options */
 	while (ptr) {
 		arg = ptr;
 		c = nc;
 		if (c == ';') {	/* Lazy pattern must be the last part */
-			pp->lazy_line = strdup(arg);
+			pp->lazy_line = xstrdup(arg);
 			break;
 		}
 		ptr = strpbrk(arg, ";:+@%");
@@ -181,8 +181,7 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 		case '@':	/* File name */
 			if (pp->file)
 				semantic_error("SRC@SRC is not allowed.");
-			pp->file = strdup(arg);
-			DIE_IF(pp->file == NULL);
+			pp->file = xstrdup(arg);
 			break;
 		case '%':	/* Probe places */
 			if (strcmp(arg, "return") == 0) {
@@ -247,11 +246,9 @@ void parse_perf_probe_event(const char *str, struct probe_point *pp,
 
 	/* Copy arguments and ensure return probe has no C argument */
 	pp->nr_args = argc - 1;
-	pp->args = zalloc(sizeof(char *) * pp->nr_args);
+	pp->args = xzalloc(sizeof(char *) * pp->nr_args);
 	for (i = 0; i < pp->nr_args; i++) {
-		pp->args[i] = strdup(argv[i + 1]);
-		if (!pp->args[i])
-			die("Failed to copy argument.");
+		pp->args[i] = xstrdup(argv[i + 1]);
 		if (is_c_varname(pp->args[i])) {
 			if (pp->retprobe)
 				semantic_error("You can't specify local"
@@ -299,14 +296,12 @@ void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
 	pp->file = NULL;
 
 	pp->nr_args = argc - 2;
-	pp->args = zalloc(sizeof(char *) * pp->nr_args);
+	pp->args = xzalloc(sizeof(char *) * pp->nr_args);
 	for (i = 0; i < pp->nr_args; i++) {
 		p = strchr(argv[i + 2], '=');
 		if (p)	/* We don't need which register is assigned. */
 			*p = '\0';
-		pp->args[i] = strdup(argv[i + 2]);
-		if (!pp->args[i])
-			die("Failed to copy argument.");
+		pp->args[i] = xstrdup(argv[i + 2]);
 	}
 
 	argv_free(argv);
@@ -319,10 +314,8 @@ int synthesize_perf_probe_point(struct probe_point *pp)
 	char offs[64] = "", line[64] = "";
 	int ret;
 
-	pp->probes[0] = buf = zalloc(MAX_CMDLEN);
+	pp->probes[0] = buf = xzalloc(MAX_CMDLEN);
 	pp->found = 1;
-	if (!buf)
-		die("Failed to allocate memory by zalloc.");
 	if (pp->offset) {
 		ret = e_snprintf(offs, 64, "+%d", pp->offset);
 		if (ret <= 0)
@@ -380,9 +373,7 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
 	char *buf;
 	int i, len, ret;
 
-	pp->probes[0] = buf = zalloc(MAX_CMDLEN);
-	if (!buf)
-		die("Failed to allocate memory by zalloc.");
+	pp->probes[0] = buf = xzalloc(MAX_CMDLEN);
 	ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
 	if (ret <= 0)
 		goto error;
@@ -612,10 +603,9 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
 	for (j = 0; j < nr_probes; j++) {
 		pp = probes + j;
 		if (!pp->event)
-			pp->event = strdup(pp->function);
+			pp->event = xstrdup(pp->function);
 		if (!pp->group)
-			pp->group = strdup(PERFPROBE_GROUP);
-		DIE_IF(!pp->event || !pp->group);
+			pp->group = xstrdup(PERFPROBE_GROUP);
 		/* If force_add is true, suffix search is allowed */
 		allow_suffix = force_add;
 		for (i = 0; i < pp->found; i++) {
@@ -709,9 +699,7 @@ void del_trace_kprobe_events(struct strlist *dellist)
 	namelist = get_perf_event_names(fd, true);
 
 	strlist__for_each(ent, dellist) {
-		str = strdup(ent->s);
-		if (!str)
-			die("Failed to copy event.");
+		str = xstrdup(ent->s);
 		pr_debug("Parsing: %s\n", str);
 		p = strchr(str, ':');
 		if (p) {
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c171a24..e887bb6 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -125,8 +125,7 @@ static void line_list__add_line(struct list_head *head, unsigned int line)
 	p = head;
 found:
 	pr_debug("line list: add a line %u\n", line);
-	ln = zalloc(sizeof(struct line_node));
-	DIE_IF(ln == NULL);
+	ln = xzalloc(sizeof(struct line_node));
 	ln->line = line;
 	INIT_LIST_HEAD(&ln->list);
 	list_add(&ln->list, p);
@@ -416,7 +415,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 				(unsigned long)(pf->addr - eaddr));
 		/* Copy the function name if possible */
 		if (!pp->function) {
-			pp->function = strdup(name);
+			pp->function = xstrdup(name);
 			pp->offset = (size_t)(pf->addr - eaddr);
 		}
 	} else {
@@ -425,7 +424,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 			       (uintmax_t)pf->addr);
 		if (!pp->function) {
 			/* TODO: Use _stext */
-			pp->function = strdup("");
+			pp->function = xstrdup("");
 			pp->offset = (size_t)pf->addr;
 		}
 	}
@@ -456,7 +455,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 	if (pp->found == MAX_PROBES)
 		die("Too many( > %d) probe point found.\n", MAX_PROBES);
 
-	pp->probes[pp->found] = strdup(tmp);
+	pp->probes[pp->found] = xstrdup(tmp);
 	pp->found++;
 }
 
@@ -506,8 +505,7 @@ static int find_lazy_match_lines(struct list_head *head,
 	if (fd < 0)
 		die("failed to open %s", fname);
 	DIE_IF(fstat(fd, &st) < 0);
-	fbuf = malloc(st.st_size + 2);
-	DIE_IF(fbuf == NULL);
+	fbuf = xmalloc(st.st_size + 2);
 	DIE_IF(read(fd, fbuf, st.st_size) < 0);
 	close(fd);
 	fbuf[st.st_size] = '\n';	/* Dummy line */
@@ -727,7 +725,7 @@ static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 
 		/* Copy real path */
 		if (!lf->lr->path)
-			lf->lr->path = strdup(src);
+			lf->lr->path = xstrdup(src);
 		line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
 	}
 	/* Update status */

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

* [tip:perf/core] perf probe: Move add-probe routine to util/
  2010-03-16 22:05 ` [PATCH -tip 03/10] perf probe: Move add-probe routine under util/ Masami Hiramatsu
@ 2010-03-17 11:28   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-03-17 11:28 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, paulus, acme, hpa, mingo, a.p.zijlstra, efault,
	dle-develop, fweisbec, tglx, mhiramat, mingo, systemtap

Commit-ID:  e0faa8d35845bb1893cf9e608a5a5d92e9390bf0
Gitweb:     http://git.kernel.org/tip/e0faa8d35845bb1893cf9e608a5a5d92e9390bf0
Author:     Masami Hiramatsu <mhiramat@redhat.com>
AuthorDate: Tue, 16 Mar 2010 18:05:37 -0400
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Wed, 17 Mar 2010 11:32:30 +0100

perf probe: Move add-probe routine to util/

Move add-probe routine to util/probe_event.c. This simplifies
main routine for reducing maintenance cost.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220537.32050.72214.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 tools/perf/builtin-probe.c    |  126 +------------------------------------
 tools/perf/util/probe-event.c |  137 ++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/probe-event.h |    2 +-
 3 files changed, 139 insertions(+), 126 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index b6afe7b..2087034 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -36,11 +36,9 @@
 #include "builtin.h"
 #include "util/util.h"
 #include "util/strlist.h"
-#include "util/event.h"
+#include "util/symbol.h"
 #include "util/debug.h"
 #include "util/debugfs.h"
-#include "util/symbol.h"
-#include "util/thread.h"
 #include "util/parse-options.h"
 #include "util/parse-events.h"	/* For debugfs_path */
 #include "util/probe-finder.h"
@@ -57,8 +55,6 @@ static struct {
 	int nr_probe;
 	struct probe_point probes[MAX_PROBES];
 	struct strlist *dellist;
-	struct map_groups kmap_groups;
-	struct map *kmaps[MAP__NR_TYPES];
 	struct line_range line_range;
 } session;
 
@@ -114,29 +110,7 @@ static int opt_del_probe_event(const struct option *opt __used,
 	return 0;
 }
 
-/* Currently just checking function name from symbol map */
-static void evaluate_probe_point(struct probe_point *pp)
-{
-	struct symbol *sym;
-	sym = map__find_symbol_by_name(session.kmaps[MAP__FUNCTION],
-				       pp->function, NULL);
-	if (!sym)
-		die("Kernel symbol \'%s\' not found - probe not added.",
-		    pp->function);
-}
-
 #ifndef NO_DWARF_SUPPORT
-static int open_vmlinux(void)
-{
-	if (map__load(session.kmaps[MAP__FUNCTION], NULL) < 0) {
-		pr_debug("Failed to load kernel map.\n");
-		return -EINVAL;
-	}
-	pr_debug("Try to open %s\n",
-		 session.kmaps[MAP__FUNCTION]->dso->long_name);
-	return open(session.kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
-}
-
 static int opt_show_lines(const struct option *opt __used,
 			  const char *str, int unset __used)
 {
@@ -204,31 +178,8 @@ static const struct option options[] = {
 	OPT_END()
 };
 
-/* Initialize symbol maps for vmlinux */
-static void init_vmlinux(void)
-{
-	symbol_conf.sort_by_name = true;
-	if (symbol_conf.vmlinux_name == NULL)
-		symbol_conf.try_vmlinux_path = true;
-	else
-		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
-	if (symbol__init() < 0)
-		die("Failed to init symbol map.");
-
-	map_groups__init(&session.kmap_groups);
-	if (map_groups__create_kernel_maps(&session.kmap_groups,
-					   session.kmaps) < 0)
-		die("Failed to create kernel maps.");
-}
-
 int cmd_probe(int argc, const char **argv, const char *prefix __used)
 {
-	int i, ret;
-#ifndef NO_DWARF_SUPPORT
-	int fd;
-#endif
-	struct probe_point *pp;
-
 	argc = parse_options(argc, argv, options, probe_usage,
 			     PARSE_OPT_STOP_AT_NON_OPTION);
 	if (argc > 0) {
@@ -267,14 +218,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 				   " --add/--del.\n");
 			usage_with_options(probe_usage, options);
 		}
-		init_vmlinux();
-		fd = open_vmlinux();
-		if (fd < 0)
-			die("Could not open debuginfo file.");
-		ret = find_line_range(fd, &session.line_range);
-		if (ret <= 0)
-			die("Source line is not found.\n");
-		close(fd);
+
 		show_line_range(&session.line_range);
 		return 0;
 	}
@@ -287,72 +231,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			return 0;
 	}
 
-	/* Add probes */
-	init_vmlinux();
-
-	if (session.need_dwarf)
-#ifdef NO_DWARF_SUPPORT
-		die("Debuginfo-analysis is not supported");
-#else	/* !NO_DWARF_SUPPORT */
-		pr_debug("Some probes require debuginfo.\n");
-
-	fd = open_vmlinux();
-	if (fd < 0) {
-		if (session.need_dwarf)
-			die("Could not open debuginfo file.");
-
-		pr_debug("Could not open vmlinux/module file."
-			 " Try to use symbols.\n");
-		goto end_dwarf;
-	}
-
-	/* Searching probe points */
-	for (i = 0; i < session.nr_probe; i++) {
-		pp = &session.probes[i];
-		if (pp->found)
-			continue;
-
-		lseek(fd, SEEK_SET, 0);
-		ret = find_probe_point(fd, pp);
-		if (ret > 0)
-			continue;
-		if (ret == 0) {	/* No error but failed to find probe point. */
-			synthesize_perf_probe_point(pp);
-			die("Probe point '%s' not found. - probe not added.",
-			    pp->probes[0]);
-		}
-		/* Error path */
-		if (session.need_dwarf) {
-			if (ret == -ENOENT)
-				pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
-			die("Could not analyze debuginfo.");
-		}
-		pr_debug("An error occurred in debuginfo analysis."
-			 " Try to use symbols.\n");
-		break;
-	}
-	close(fd);
-
-end_dwarf:
-#endif /* !NO_DWARF_SUPPORT */
-
-	/* Synthesize probes without dwarf */
-	for (i = 0; i < session.nr_probe; i++) {
-		pp = &session.probes[i];
-		if (pp->found)	/* This probe is already found. */
-			continue;
-
-		evaluate_probe_point(pp);
-		ret = synthesize_trace_kprobe_event(pp);
-		if (ret == -E2BIG)
-			die("probe point definition becomes too long.");
-		else if (ret < 0)
-			die("Failed to synthesize a probe point.");
-	}
-
-	/* Settng up probe points */
 	add_trace_kprobe_events(session.probes, session.nr_probe,
-				session.force_add);
+				session.force_add, session.need_dwarf);
 	return 0;
 }
 
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 88a3b6d..1e60a65 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -40,6 +40,8 @@
 #include "debug.h"
 #include "cache.h"
 #include "color.h"
+#include "symbol.h"
+#include "thread.h"
 #include "parse-events.h"  /* For debugfs_path */
 #include "probe-event.h"
 
@@ -65,6 +67,38 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 	return ret;
 }
 
+
+static struct map_groups kmap_groups;
+static struct map *kmaps[MAP__NR_TYPES];
+
+/* Initialize symbol maps for vmlinux */
+static void init_vmlinux(void)
+{
+	symbol_conf.sort_by_name = true;
+	if (symbol_conf.vmlinux_name == NULL)
+		symbol_conf.try_vmlinux_path = true;
+	else
+		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
+	if (symbol__init() < 0)
+		die("Failed to init symbol map.");
+
+	map_groups__init(&kmap_groups);
+	if (map_groups__create_kernel_maps(&kmap_groups, kmaps) < 0)
+		die("Failed to create kernel maps.");
+}
+
+#ifndef NO_DWARF_SUPPORT
+static int open_vmlinux(void)
+{
+	if (map__load(kmaps[MAP__FUNCTION], NULL) < 0) {
+		pr_debug("Failed to load kernel map.\n");
+		return -EINVAL;
+	}
+	pr_debug("Try to open %s\n", kmaps[MAP__FUNCTION]->dso->long_name);
+	return open(kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
+}
+#endif
+
 void parse_line_range_desc(const char *arg, struct line_range *lr)
 {
 	const char *ptr;
@@ -586,8 +620,8 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
 		die("Too many events are on the same function.");
 }
 
-void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
-			     bool force_add)
+static void __add_trace_kprobe_events(struct probe_point *probes,
+				      int nr_probes, bool force_add)
 {
 	int i, j, fd;
 	struct probe_point *pp;
@@ -640,6 +674,92 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
 	close(fd);
 }
 
+/* Currently just checking function name from symbol map */
+static void evaluate_probe_point(struct probe_point *pp)
+{
+	struct symbol *sym;
+	sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
+				       pp->function, NULL);
+	if (!sym)
+		die("Kernel symbol \'%s\' not found - probe not added.",
+		    pp->function);
+}
+
+void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
+			     bool force_add, bool need_dwarf)
+{
+	int i, ret;
+	struct probe_point *pp;
+#ifndef NO_DWARF_SUPPORT
+	int fd;
+#endif
+	/* Add probes */
+	init_vmlinux();
+
+	if (need_dwarf)
+#ifdef NO_DWARF_SUPPORT
+		die("Debuginfo-analysis is not supported");
+#else	/* !NO_DWARF_SUPPORT */
+		pr_debug("Some probes require debuginfo.\n");
+
+	fd = open_vmlinux();
+	if (fd < 0) {
+		if (need_dwarf)
+			die("Could not open debuginfo file.");
+
+		pr_debug("Could not open vmlinux/module file."
+			 " Try to use symbols.\n");
+		goto end_dwarf;
+	}
+
+	/* Searching probe points */
+	for (i = 0; i < nr_probes; i++) {
+		pp = &probes[i];
+		if (pp->found)
+			continue;
+
+		lseek(fd, SEEK_SET, 0);
+		ret = find_probe_point(fd, pp);
+		if (ret > 0)
+			continue;
+		if (ret == 0) {	/* No error but failed to find probe point. */
+			synthesize_perf_probe_point(pp);
+			die("Probe point '%s' not found. - probe not added.",
+			    pp->probes[0]);
+		}
+		/* Error path */
+		if (need_dwarf) {
+			if (ret == -ENOENT)
+				pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
+			die("Could not analyze debuginfo.");
+		}
+		pr_debug("An error occurred in debuginfo analysis."
+			 " Try to use symbols.\n");
+		break;
+	}
+	close(fd);
+
+end_dwarf:
+#endif /* !NO_DWARF_SUPPORT */
+
+	/* Synthesize probes without dwarf */
+	for (i = 0; i < nr_probes; i++) {
+		pp = &probes[i];
+		if (pp->found)	/* This probe is already found. */
+			continue;
+
+		evaluate_probe_point(pp);
+		ret = synthesize_trace_kprobe_event(pp);
+		if (ret == -E2BIG)
+			die("probe point definition becomes too long.");
+		else if (ret < 0)
+			die("Failed to synthesize a probe point.");
+	}
+
+	/* Settng up probe points */
+	__add_trace_kprobe_events(probes, nr_probes, force_add);
+}
+
 static void __del_trace_kprobe_event(int fd, struct str_node *ent)
 {
 	char *p;
@@ -759,6 +879,17 @@ void show_line_range(struct line_range *lr)
 	unsigned int l = 1;
 	struct line_node *ln;
 	FILE *fp;
+	int fd, ret;
+
+	/* Search a line range */
+	init_vmlinux();
+	fd = open_vmlinux();
+	if (fd < 0)
+		die("Could not open debuginfo file.");
+	ret = find_line_range(fd, lr);
+	if (ret <= 0)
+		die("Source line is not found.\n");
+	close(fd);
 
 	setup_pager();
 
@@ -788,3 +919,5 @@ void show_line_range(struct line_range *lr)
 
 	fclose(fp);
 }
+
+
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 711287d..3865e16 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -13,7 +13,7 @@ extern int synthesize_perf_probe_event(struct probe_point *pp);
 extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
 extern int synthesize_trace_kprobe_event(struct probe_point *pp);
 extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
-				    bool force_add);
+				    bool force_add, bool need_dwarf);
 extern void del_trace_kprobe_events(struct strlist *dellist);
 extern void show_perf_probe_events(void);
 extern void show_line_range(struct line_range *lr);

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

* [tip:perf/core] perf probe: Rename session to param
  2010-03-16 22:05 ` [PATCH -tip 04/10] perf probe: Rename session to param Masami Hiramatsu
@ 2010-03-17 11:28   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-03-17 11:28 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, paulus, acme, hpa, mingo, a.p.zijlstra, efault,
	dle-develop, fweisbec, tglx, mhiramat, mingo, systemtap

Commit-ID:  12a1fadb41b5a6733c36b488b881fb19a28c92d3
Gitweb:     http://git.kernel.org/tip/12a1fadb41b5a6733c36b488b881fb19a28c92d3
Author:     Masami Hiramatsu <mhiramat@redhat.com>
AuthorDate: Tue, 16 Mar 2010 18:05:44 -0400
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Wed, 17 Mar 2010 11:32:30 +0100

perf probe: Rename session to param

Since this name 'session' conflicts with 'perf_session', and
this structure just holds parameters anymore.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220544.32050.8788.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 tools/perf/builtin-probe.c |   54 ++++++++++++++++++++++----------------------
 1 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 2087034..f577e14 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -56,20 +56,20 @@ static struct {
 	struct probe_point probes[MAX_PROBES];
 	struct strlist *dellist;
 	struct line_range line_range;
-} session;
+} params;
 
 
 /* Parse an event definition. Note that any error must die. */
 static void parse_probe_event(const char *str)
 {
-	struct probe_point *pp = &session.probes[session.nr_probe];
+	struct probe_point *pp = &params.probes[params.nr_probe];
 
-	pr_debug("probe-definition(%d): %s\n", session.nr_probe, str);
-	if (++session.nr_probe == MAX_PROBES)
+	pr_debug("probe-definition(%d): %s\n", params.nr_probe, str);
+	if (++params.nr_probe == MAX_PROBES)
 		die("Too many probes (> %d) are specified.", MAX_PROBES);
 
 	/* Parse perf-probe event into probe_point */
-	parse_perf_probe_event(str, pp, &session.need_dwarf);
+	parse_perf_probe_event(str, pp, &params.need_dwarf);
 
 	pr_debug("%d arguments\n", pp->nr_args);
 }
@@ -103,9 +103,9 @@ static int opt_del_probe_event(const struct option *opt __used,
 			       const char *str, int unset __used)
 {
 	if (str) {
-		if (!session.dellist)
-			session.dellist = strlist__new(true, NULL);
-		strlist__add(session.dellist, str);
+		if (!params.dellist)
+			params.dellist = strlist__new(true, NULL);
+		strlist__add(params.dellist, str);
 	}
 	return 0;
 }
@@ -115,9 +115,9 @@ static int opt_show_lines(const struct option *opt __used,
 			  const char *str, int unset __used)
 {
 	if (str)
-		parse_line_range_desc(str, &session.line_range);
-	INIT_LIST_HEAD(&session.line_range.line_list);
-	session.show_lines = true;
+		parse_line_range_desc(str, &params.line_range);
+	INIT_LIST_HEAD(&params.line_range.line_list);
+	params.show_lines = true;
 	return 0;
 }
 #endif
@@ -140,7 +140,7 @@ static const struct option options[] = {
 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 		   "file", "vmlinux pathname"),
 #endif
-	OPT_BOOLEAN('l', "list", &session.list_events,
+	OPT_BOOLEAN('l', "list", &params.list_events,
 		    "list up current probe events"),
 	OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
 		opt_del_probe_event),
@@ -168,7 +168,7 @@ static const struct option options[] = {
 #endif
 		"\t\t\tkprobe-tracer argument format.)\n",
 		opt_add_probe_event),
-	OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events"
+	OPT_BOOLEAN('f', "force", &params.force_add, "forcibly add events"
 		    " with existing name"),
 #ifndef NO_DWARF_SUPPORT
 	OPT_CALLBACK('L', "line", NULL,
@@ -190,20 +190,20 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		parse_probe_event_argv(argc, argv);
 	}
 
-	if ((!session.nr_probe && !session.dellist && !session.list_events &&
-	     !session.show_lines))
+	if ((!params.nr_probe && !params.dellist && !params.list_events &&
+	     !params.show_lines))
 		usage_with_options(probe_usage, options);
 
 	if (debugfs_valid_mountpoint(debugfs_path) < 0)
 		die("Failed to find debugfs path.");
 
-	if (session.list_events) {
-		if (session.nr_probe != 0 || session.dellist) {
+	if (params.list_events) {
+		if (params.nr_probe != 0 || params.dellist) {
 			pr_warning("  Error: Don't use --list with"
 				   " --add/--del.\n");
 			usage_with_options(probe_usage, options);
 		}
-		if (session.show_lines) {
+		if (params.show_lines) {
 			pr_warning("  Error: Don't use --list with --line.\n");
 			usage_with_options(probe_usage, options);
 		}
@@ -212,27 +212,27 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 	}
 
 #ifndef NO_DWARF_SUPPORT
-	if (session.show_lines) {
-		if (session.nr_probe != 0 || session.dellist) {
+	if (params.show_lines) {
+		if (params.nr_probe != 0 || params.dellist) {
 			pr_warning("  Error: Don't use --line with"
 				   " --add/--del.\n");
 			usage_with_options(probe_usage, options);
 		}
 
-		show_line_range(&session.line_range);
+		show_line_range(&params.line_range);
 		return 0;
 	}
 #endif
 
-	if (session.dellist) {
-		del_trace_kprobe_events(session.dellist);
-		strlist__delete(session.dellist);
-		if (session.nr_probe == 0)
+	if (params.dellist) {
+		del_trace_kprobe_events(params.dellist);
+		strlist__delete(params.dellist);
+		if (params.nr_probe == 0)
 			return 0;
 	}
 
-	add_trace_kprobe_events(session.probes, session.nr_probe,
-				session.force_add, session.need_dwarf);
+	add_trace_kprobe_events(params.probes, params.nr_probe,
+				params.force_add, params.need_dwarf);
 	return 0;
 }
 

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

* [tip:perf/core] perf probe: Rename some die_get_* functions
  2010-03-16 22:05 ` [PATCH -tip 05/10] perf probe: Rename some die_get_* functions Masami Hiramatsu
@ 2010-03-17 11:28   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-03-17 11:28 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, paulus, acme, hpa, mingo, a.p.zijlstra, efault,
	dle-develop, fweisbec, tglx, mhiramat, mingo, systemtap

Commit-ID:  95a3e4c4e21de1920a2ddb54bfc57c0af7e2561e
Gitweb:     http://git.kernel.org/tip/95a3e4c4e21de1920a2ddb54bfc57c0af7e2561e
Author:     Masami Hiramatsu <mhiramat@redhat.com>
AuthorDate: Tue, 16 Mar 2010 18:05:51 -0400
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Wed, 17 Mar 2010 11:32:30 +0100

perf probe: Rename some die_get_* functions

Rename die_get_real_subprogram and die_get_inlinefunc to
die_find_real_subprogram and die_find_inlinefunc respectively,
because these functions search its children. After that,
'die_get_' means getting a property of that die, and
'die_find_' means searching DIE-tree to get an appropriate
child die.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220551.32050.36181.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 tools/perf/util/probe-finder.c |   16 ++++++++--------
 1 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index e887bb6..c91a960 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -204,8 +204,8 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
 }
 
 /* Search a real subprogram including this line, */
-static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
-					  Dwarf_Die *die_mem)
+static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
+					   Dwarf_Die *die_mem)
 {
 	struct __addr_die_search_param ad;
 	ad.addr = addr;
@@ -218,8 +218,8 @@ static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
 }
 
 /* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
-static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
-				     Dwarf_Die *die_mem)
+static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
+				      Dwarf_Die *die_mem)
 {
 	Dwarf_Die child_die;
 	int ret;
@@ -233,7 +233,7 @@ static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
 		    dwarf_haspc(die_mem, addr))
 			return die_mem;
 
-		if (die_get_inlinefunc(die_mem, addr, &child_die)) {
+		if (die_find_inlinefunc(die_mem, addr, &child_die)) {
 			memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
 			return die_mem;
 		}
@@ -401,7 +401,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 
 	/* If no real subprogram, find a real one */
 	if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
-		sp_die = die_get_real_subprogram(&pf->cu_die,
+		sp_die = die_find_real_subprogram(&pf->cu_die,
 						 pf->addr, &die_mem);
 		if (!sp_die)
 			die("Probe point is not found in subprograms.");
@@ -564,7 +564,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 			if (!dwarf_haspc(sp_die, addr))
 				continue;
 			/* Address filtering 2: No child include addr? */
-			if (die_get_inlinefunc(sp_die, addr, &die_mem))
+			if (die_find_inlinefunc(sp_die, addr, &die_mem))
 				continue;
 		}
 
@@ -714,7 +714,7 @@ static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 				continue;
 
 			/* Address filtering 2: No child include addr? */
-			if (die_get_inlinefunc(sp_die, addr, &die_mem))
+			if (die_find_inlinefunc(sp_die, addr, &die_mem))
 				continue;
 		}
 

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

* [tip:perf/core] perf probe: Introduce die_find_child() function
  2010-03-16 22:05 ` [PATCH -tip 06/10] perf probe: Introduce die_find_child() function Masami Hiramatsu
@ 2010-03-17 11:29   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-03-17 11:29 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, paulus, acme, hpa, mingo, a.p.zijlstra, efault,
	dle-develop, fweisbec, tglx, mhiramat, mingo, systemtap

Commit-ID:  016f262e4fb10c6ecff709317098912f94a21efa
Gitweb:     http://git.kernel.org/tip/016f262e4fb10c6ecff709317098912f94a21efa
Author:     Masami Hiramatsu <mhiramat@redhat.com>
AuthorDate: Tue, 16 Mar 2010 18:05:58 -0400
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Wed, 17 Mar 2010 11:32:31 +0100

perf probe: Introduce die_find_child() function

Introduce die_find_child() function to integrate DIE-tree
searching functions.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220558.32050.7905.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 tools/perf/util/probe-finder.c |  136 +++++++++++++++++++++++----------------
 1 files changed, 80 insertions(+), 56 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c91a960..3942e14 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -186,6 +186,62 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
 	return src;
 }
 
+/* Compare diename and tname */
+static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
+{
+	const char *name;
+	name = dwarf_diename(dw_die);
+	DIE_IF(name == NULL);
+	return strcmp(tname, name);
+}
+
+/* Get entry pc(or low pc, 1st entry of ranges)  of the die */
+static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
+{
+	Dwarf_Addr epc;
+	int ret;
+
+	ret = dwarf_entrypc(dw_die, &epc);
+	DIE_IF(ret == -1);
+	return epc;
+}
+
+/* Return values for die_find callbacks */
+enum {
+	DIE_FIND_CB_FOUND = 0,		/* End of Search */
+	DIE_FIND_CB_CHILD = 1,		/* Search only children */
+	DIE_FIND_CB_SIBLING = 2,	/* Search only siblings */
+	DIE_FIND_CB_CONTINUE = 3,	/* Search children and siblings */
+};
+
+/* Search a child die */
+static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
+				 int (*callback)(Dwarf_Die *, void *),
+				 void *data, Dwarf_Die *die_mem)
+{
+	Dwarf_Die child_die;
+	int ret;
+
+	ret = dwarf_child(rt_die, die_mem);
+	if (ret != 0)
+		return NULL;
+
+	do {
+		ret = callback(die_mem, data);
+		if (ret == DIE_FIND_CB_FOUND)
+			return die_mem;
+
+		if ((ret & DIE_FIND_CB_CHILD) &&
+		    die_find_child(die_mem, callback, data, &child_die)) {
+			memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
+			return die_mem;
+		}
+	} while ((ret & DIE_FIND_CB_SIBLING) &&
+		 dwarf_siblingof(die_mem, die_mem) == 0);
+
+	return NULL;
+}
+
 struct __addr_die_search_param {
 	Dwarf_Addr	addr;
 	Dwarf_Die	*die_mem;
@@ -217,77 +273,45 @@ static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
 		return die_mem;
 }
 
-/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
-static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
-				      Dwarf_Die *die_mem)
+/* die_find callback for inline function search */
+static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
 {
-	Dwarf_Die child_die;
-	int ret;
+	Dwarf_Addr *addr = data;
 
-	ret = dwarf_child(sp_die, die_mem);
-	if (ret != 0)
-		return NULL;
-
-	do {
-		if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
-		    dwarf_haspc(die_mem, addr))
-			return die_mem;
+	if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
+	    dwarf_haspc(die_mem, *addr))
+		return DIE_FIND_CB_FOUND;
 
-		if (die_find_inlinefunc(die_mem, addr, &child_die)) {
-			memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
-			return die_mem;
-		}
-	} while (dwarf_siblingof(die_mem, die_mem) == 0);
-
-	return NULL;
+	return DIE_FIND_CB_CONTINUE;
 }
 
-/* Compare diename and tname */
-static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
+/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
+static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
+				      Dwarf_Die *die_mem)
 {
-	const char *name;
-	name = dwarf_diename(dw_die);
-	DIE_IF(name == NULL);
-	return strcmp(tname, name);
+	return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
 }
 
-/* Get entry pc(or low pc, 1st entry of ranges)  of the die */
-static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
+static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
 {
-	Dwarf_Addr epc;
-	int ret;
+	const char *name = data;
+	int tag;
 
-	ret = dwarf_entrypc(dw_die, &epc);
-	DIE_IF(ret == -1);
-	return epc;
+	tag = dwarf_tag(die_mem);
+	if ((tag == DW_TAG_formal_parameter ||
+	     tag == DW_TAG_variable) &&
+	    (die_compare_name(die_mem, name) == 0))
+		return DIE_FIND_CB_FOUND;
+
+	return DIE_FIND_CB_CONTINUE;
 }
 
-/* Get a variable die */
+/* Find a variable called 'name' */
 static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
 				    Dwarf_Die *die_mem)
 {
-	Dwarf_Die child_die;
-	int tag;
-	int ret;
-
-	ret = dwarf_child(sp_die, die_mem);
-	if (ret != 0)
-		return NULL;
-
-	do {
-		tag = dwarf_tag(die_mem);
-		if ((tag == DW_TAG_formal_parameter ||
-		     tag == DW_TAG_variable) &&
-		    (die_compare_name(die_mem, name) == 0))
-			return die_mem;
-
-		if (die_find_variable(die_mem, name, &child_die)) {
-			memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
-			return die_mem;
-		}
-	} while (dwarf_siblingof(die_mem, die_mem) == 0);
-
-	return NULL;
+	return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
+			      die_mem);
 }
 
 /*

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

* [tip:perf/core] perf probe: Add --dry-run option
  2010-03-16 22:06 ` [PATCH -tip 07/10] perf probe: Add --dry-run option Masami Hiramatsu
@ 2010-03-17 11:29   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-03-17 11:29 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, paulus, acme, hpa, mingo, a.p.zijlstra, efault,
	dle-develop, fweisbec, tglx, mhiramat, mingo, systemtap

Commit-ID:  f4d7da499e4fc1fdff8f26fdeb1a058d475a7a6c
Gitweb:     http://git.kernel.org/tip/f4d7da499e4fc1fdff8f26fdeb1a058d475a7a6c
Author:     Masami Hiramatsu <mhiramat@redhat.com>
AuthorDate: Tue, 16 Mar 2010 18:06:05 -0400
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Wed, 17 Mar 2010 11:32:31 +0100

perf probe: Add --dry-run option

Add --dry-run option for debugging and testing.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220605.32050.6571.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 tools/perf/Documentation/perf-probe.txt |    5 +++++
 tools/perf/builtin-probe.c              |    1 +
 tools/perf/util/probe-event.c           |   24 ++++++++++++++++--------
 tools/perf/util/probe-event.h           |    2 ++
 4 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 34202b1..0f944b3 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -57,6 +57,11 @@ OPTIONS
 --force::
 	Forcibly add events with existing name.
 
+-n::
+--dry-run::
+	Dry run. With this option, --add and --del doesn't execute actual
+	adding and removal operations.
+
 PROBE SYNTAX
 ------------
 Probe points are defined by following syntax.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index f577e14..a1a2891 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -175,6 +175,7 @@ static const struct option options[] = {
 		     "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]",
 		     "Show source code lines.", opt_show_lines),
 #endif
+	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_END()
 };
 
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1e60a65..ac41578 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -49,6 +49,8 @@
 #define MAX_PROBE_ARGS 128
 #define PERFPROBE_GROUP "probe"
 
+bool probe_event_dry_run;	/* Dry run flag */
+
 #define semantic_error(msg ...) die("Semantic error :" msg)
 
 /* If there is no space to write, returns -E2BIG. */
@@ -430,7 +432,7 @@ error:
 	return ret;
 }
 
-static int open_kprobe_events(int flags, int mode)
+static int open_kprobe_events(bool readwrite)
 {
 	char buf[PATH_MAX];
 	int ret;
@@ -439,7 +441,11 @@ static int open_kprobe_events(int flags, int mode)
 	if (ret < 0)
 		die("Failed to make kprobe_events path.");
 
-	ret = open(buf, flags, mode);
+	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)
 			die("kprobe_events file does not exist -"
@@ -535,7 +541,7 @@ void show_perf_probe_events(void)
 	setup_pager();
 	memset(&pp, 0, sizeof(pp));
 
-	fd = open_kprobe_events(O_RDONLY, 0);
+	fd = open_kprobe_events(false);
 	rawlist = get_trace_kprobe_event_rawlist(fd);
 	close(fd);
 
@@ -585,9 +591,11 @@ static void write_trace_kprobe_event(int fd, const char *buf)
 	int ret;
 
 	pr_debug("Writing event: %s\n", buf);
-	ret = write(fd, buf, strlen(buf));
-	if (ret <= 0)
-		die("Failed to write event: %s", strerror(errno));
+	if (!probe_event_dry_run) {
+		ret = write(fd, buf, strlen(buf));
+		if (ret <= 0)
+			die("Failed to write event: %s", strerror(errno));
+	}
 }
 
 static void get_new_event_name(char *buf, size_t len, const char *base,
@@ -630,7 +638,7 @@ static void __add_trace_kprobe_events(struct probe_point *probes,
 	struct strlist *namelist;
 	bool allow_suffix;
 
-	fd = open_kprobe_events(O_RDWR, O_APPEND);
+	fd = open_kprobe_events(true);
 	/* Get current event names */
 	namelist = get_perf_event_names(fd, false);
 
@@ -814,7 +822,7 @@ void del_trace_kprobe_events(struct strlist *dellist)
 	struct str_node *ent;
 	struct strlist *namelist;
 
-	fd = open_kprobe_events(O_RDWR, O_APPEND);
+	fd = open_kprobe_events(true);
 	/* Get current event names */
 	namelist = get_perf_event_names(fd, true);
 
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 3865e16..703b887 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -5,6 +5,8 @@
 #include "probe-finder.h"
 #include "strlist.h"
 
+extern bool probe_event_dry_run;
+
 extern void parse_line_range_desc(const char *arg, struct line_range *lr);
 extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
 				   bool *need_dwarf);

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

* [tip:perf/core] perf probe: Introduce kprobe_trace_event and perf_probe_event
  2010-03-16 22:06 ` [PATCH -tip 08/10] perf probe: Introduce kprobe_trace_event and perf_probe_event Masami Hiramatsu
@ 2010-03-17 11:29   ` tip-bot for Masami Hiramatsu
  2010-03-17 11:30   ` [tip:perf/core] perf probe: Fix !dwarf build tip-bot for Ingo Molnar
  2010-03-18 17:38   ` [tip:perf/core] perf events: Fix false positive build warning with older GCC's tip-bot for Ingo Molnar
  2 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-03-17 11:29 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, paulus, acme, hpa, mingo, a.p.zijlstra, efault,
	dle-develop, fweisbec, tglx, mhiramat, mingo, systemtap

Commit-ID:  4235b0454ebeefc2295ad8417e18a8761425b19e
Gitweb:     http://git.kernel.org/tip/4235b0454ebeefc2295ad8417e18a8761425b19e
Author:     Masami Hiramatsu <mhiramat@redhat.com>
AuthorDate: Tue, 16 Mar 2010 18:06:12 -0400
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Wed, 17 Mar 2010 11:32:31 +0100

perf probe: Introduce kprobe_trace_event and perf_probe_event

Introduce kprobe_trace_event and perf_probe_event and replace
old probe_point structure with it. probe_point structure is
not enough flexible nor extensible. New data structures
will help implementing further features.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220612.32050.33806.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 tools/perf/builtin-probe.c     |   30 +-
 tools/perf/util/probe-event.c  |  628 +++++++++++++++++++++++++---------------
 tools/perf/util/probe-event.h  |  111 +++++++-
 tools/perf/util/probe-finder.c |  140 ++++-----
 tools/perf/util/probe-finder.h |   58 +---
 5 files changed, 590 insertions(+), 377 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index a1a2891..e0dafd9 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -48,12 +48,11 @@
 
 /* Session management structure */
 static struct {
-	bool need_dwarf;
 	bool list_events;
 	bool force_add;
 	bool show_lines;
-	int nr_probe;
-	struct probe_point probes[MAX_PROBES];
+	int nevents;
+	struct perf_probe_event events[MAX_PROBES];
 	struct strlist *dellist;
 	struct line_range line_range;
 } params;
@@ -62,16 +61,16 @@ static struct {
 /* Parse an event definition. Note that any error must die. */
 static void parse_probe_event(const char *str)
 {
-	struct probe_point *pp = &params.probes[params.nr_probe];
+	struct perf_probe_event *pev = &params.events[params.nevents];
 
-	pr_debug("probe-definition(%d): %s\n", params.nr_probe, str);
-	if (++params.nr_probe == MAX_PROBES)
+	pr_debug("probe-definition(%d): %s\n", params.nevents, str);
+	if (++params.nevents == MAX_PROBES)
 		die("Too many probes (> %d) are specified.", MAX_PROBES);
 
-	/* Parse perf-probe event into probe_point */
-	parse_perf_probe_event(str, pp, &params.need_dwarf);
+	/* Parse a perf-probe command into event */
+	parse_perf_probe_command(str, pev);
 
-	pr_debug("%d arguments\n", pp->nr_args);
+	pr_debug("%d arguments\n", pev->nargs);
 }
 
 static void parse_probe_event_argv(int argc, const char **argv)
@@ -191,7 +190,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		parse_probe_event_argv(argc, argv);
 	}
 
-	if ((!params.nr_probe && !params.dellist && !params.list_events &&
+	if ((!params.nevents && !params.dellist && !params.list_events &&
 	     !params.show_lines))
 		usage_with_options(probe_usage, options);
 
@@ -199,7 +198,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		die("Failed to find debugfs path.");
 
 	if (params.list_events) {
-		if (params.nr_probe != 0 || params.dellist) {
+		if (params.nevents != 0 || params.dellist) {
 			pr_warning("  Error: Don't use --list with"
 				   " --add/--del.\n");
 			usage_with_options(probe_usage, options);
@@ -214,7 +213,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 
 #ifndef NO_DWARF_SUPPORT
 	if (params.show_lines) {
-		if (params.nr_probe != 0 || params.dellist) {
+		if (params.nevents != 0 || params.dellist) {
 			pr_warning("  Error: Don't use --line with"
 				   " --add/--del.\n");
 			usage_with_options(probe_usage, options);
@@ -226,14 +225,13 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 #endif
 
 	if (params.dellist) {
-		del_trace_kprobe_events(params.dellist);
+		del_perf_probe_events(params.dellist);
 		strlist__delete(params.dellist);
-		if (params.nr_probe == 0)
+		if (params.nevents == 0)
 			return 0;
 	}
 
-	add_trace_kprobe_events(params.probes, params.nr_probe,
-				params.force_add, params.need_dwarf);
+	add_perf_probe_events(params.events, params.nevents, params.force_add);
 	return 0;
 }
 
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index ac41578..b44ddfb 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -44,6 +44,7 @@
 #include "thread.h"
 #include "parse-events.h"  /* For debugfs_path */
 #include "probe-event.h"
+#include "probe-finder.h"
 
 #define MAX_CMDLEN 256
 #define MAX_PROBE_ARGS 128
@@ -150,8 +151,9 @@ static bool check_event_name(const char *name)
 }
 
 /* Parse probepoint definition. */
-static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
+static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 {
+	struct perf_probe_point *pp = &pev->point;
 	char *ptr, *tmp;
 	char c, nc = 0;
 	/*
@@ -172,7 +174,8 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 		if (!check_event_name(arg))
 			semantic_error("%s is bad for event name -it must "
 				       "follow C symbol-naming rule.", arg);
-		pp->event = xstrdup(arg);
+		pev->event = xstrdup(arg);
+		pev->group = NULL;
 		arg = tmp;
 	}
 
@@ -255,57 +258,65 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
 		semantic_error("Offset/Line/Lazy pattern can't be used with "
 			       "return probe.");
 
-	pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n",
+	pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
 		 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
 		 pp->lazy_line);
 }
 
-/* Parse perf-probe event definition */
-void parse_perf_probe_event(const char *str, struct probe_point *pp,
-			    bool *need_dwarf)
+/* Parse perf-probe event command */
+void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
 {
 	char **argv;
 	int argc, i;
 
-	*need_dwarf = false;
-
-	argv = argv_split(str, &argc);
+	argv = argv_split(cmd, &argc);
 	if (!argv)
 		die("argv_split failed.");
 	if (argc > MAX_PROBE_ARGS + 1)
 		semantic_error("Too many arguments");
 
 	/* Parse probe point */
-	parse_perf_probe_probepoint(argv[0], pp);
-	if (pp->file || pp->line || pp->lazy_line)
-		*need_dwarf = true;
+	parse_perf_probe_point(argv[0], pev);
 
 	/* Copy arguments and ensure return probe has no C argument */
-	pp->nr_args = argc - 1;
-	pp->args = xzalloc(sizeof(char *) * pp->nr_args);
-	for (i = 0; i < pp->nr_args; i++) {
-		pp->args[i] = xstrdup(argv[i + 1]);
-		if (is_c_varname(pp->args[i])) {
-			if (pp->retprobe)
-				semantic_error("You can't specify local"
-						" variable for kretprobe");
-			*need_dwarf = true;
-		}
+	pev->nargs = argc - 1;
+	pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
+	for (i = 0; i < pev->nargs; i++) {
+		pev->args[i].name = xstrdup(argv[i + 1]);
+		if (is_c_varname(pev->args[i].name) && pev->point.retprobe)
+			semantic_error("You can't specify local variable for"
+				       " kretprobe");
 	}
 
 	argv_free(argv);
 }
 
+/* Return true if this perf_probe_event requires debuginfo */
+bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
+{
+	int i;
+
+	if (pev->point.file || pev->point.line || pev->point.lazy_line)
+		return true;
+
+	for (i = 0; i < pev->nargs; i++)
+		if (is_c_varname(pev->args[i].name))
+			return true;
+
+	return false;
+}
+
 /* Parse kprobe_events event into struct probe_point */
-void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
+void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
 {
+	struct kprobe_trace_point *tp = &tev->point;
 	char pr;
 	char *p;
 	int ret, i, argc;
 	char **argv;
 
-	pr_debug("Parsing kprobe_events: %s\n", str);
-	argv = argv_split(str, &argc);
+	pr_debug("Parsing kprobe_events: %s\n", cmd);
+	argv = argv_split(cmd, &argc);
 	if (!argv)
 		die("argv_split failed.");
 	if (argc < 2)
@@ -313,47 +324,46 @@ void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
 
 	/* Scan event and group name. */
 	ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
-		     &pr, (float *)(void *)&pp->group,
-		     (float *)(void *)&pp->event);
+		     &pr, (float *)(void *)&tev->group,
+		     (float *)(void *)&tev->event);
 	if (ret != 3)
 		semantic_error("Failed to parse event name: %s", argv[0]);
-	pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
+	pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
 
-	pp->retprobe = (pr == 'r');
+	tp->retprobe = (pr == 'r');
 
 	/* Scan function name and offset */
-	ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
-		     &pp->offset);
+	ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol,
+		     &tp->offset);
 	if (ret == 1)
-		pp->offset = 0;
-
-	/* kprobe_events doesn't have this information */
-	pp->line = 0;
-	pp->file = NULL;
+		tp->offset = 0;
 
-	pp->nr_args = argc - 2;
-	pp->args = xzalloc(sizeof(char *) * pp->nr_args);
-	for (i = 0; i < pp->nr_args; i++) {
+	tev->nargs = argc - 2;
+	tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
+	for (i = 0; i < tev->nargs; i++) {
 		p = strchr(argv[i + 2], '=');
 		if (p)	/* We don't need which register is assigned. */
-			*p = '\0';
-		pp->args[i] = xstrdup(argv[i + 2]);
+			*p++ = '\0';
+		else
+			p = argv[i + 2];
+		tev->args[i].name = xstrdup(argv[i + 2]);
+		/* TODO: parse regs and offset */
+		tev->args[i].value = xstrdup(p);
 	}
 
 	argv_free(argv);
 }
 
-/* Synthesize only probe point (not argument) */
-int synthesize_perf_probe_point(struct probe_point *pp)
+/* Compose only probe point (not argument) */
+static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 {
 	char *buf;
 	char offs[64] = "", line[64] = "";
 	int ret;
 
-	pp->probes[0] = buf = xzalloc(MAX_CMDLEN);
-	pp->found = 1;
+	buf = xzalloc(MAX_CMDLEN);
 	if (pp->offset) {
-		ret = e_snprintf(offs, 64, "+%d", pp->offset);
+		ret = e_snprintf(offs, 64, "+%lu", pp->offset);
 		if (ret <= 0)
 			goto error;
 	}
@@ -368,68 +378,209 @@ int synthesize_perf_probe_point(struct probe_point *pp)
 				 offs, pp->retprobe ? "%return" : "", line);
 	else
 		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
-	if (ret <= 0) {
+	if (ret <= 0)
+		goto error;
+
+	return buf;
 error:
-		free(pp->probes[0]);
-		pp->probes[0] = NULL;
-		pp->found = 0;
-	}
-	return ret;
+	die("Failed to synthesize perf probe point: %s", strerror(-ret));
 }
 
-int synthesize_perf_probe_event(struct probe_point *pp)
+#if 0
+char *synthesize_perf_probe_command(struct perf_probe_event *pev)
 {
 	char *buf;
 	int i, len, ret;
 
-	len = synthesize_perf_probe_point(pp);
-	if (len < 0)
-		return 0;
+	buf = synthesize_perf_probe_point(&pev->point);
+	if (!buf)
+		return NULL;
 
-	buf = pp->probes[0];
-	for (i = 0; i < pp->nr_args; i++) {
+	len = strlen(buf);
+	for (i = 0; i < pev->nargs; i++) {
 		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
-				 pp->args[i]);
-		if (ret <= 0)
-			goto error;
+				 pev->args[i].name);
+		if (ret <= 0) {
+			free(buf);
+			return NULL;
+		}
 		len += ret;
 	}
-	pp->found = 1;
 
-	return pp->found;
-error:
-	free(pp->probes[0]);
-	pp->probes[0] = NULL;
+	return buf;
+}
+#endif
+
+static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref,
+					     char **buf, size_t *buflen,
+					     int depth)
+{
+	int ret;
+	if (ref->next) {
+		depth = __synthesize_kprobe_trace_arg_ref(ref->next, buf,
+							 buflen, depth + 1);
+		if (depth < 0)
+			goto out;
+	}
+
+	ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
+	if (ret < 0)
+		depth = ret;
+	else {
+		*buf += ret;
+		*buflen -= ret;
+	}
+out:
+	return depth;
 
-	return ret;
 }
 
-int synthesize_trace_kprobe_event(struct probe_point *pp)
+static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
+				       char *buf, size_t buflen)
 {
+	int ret, depth = 0;
+	char *tmp = buf;
+
+	/* Argument name or separator */
+	if (arg->name)
+		ret = e_snprintf(buf, buflen, " %s=", arg->name);
+	else
+		ret = e_snprintf(buf, buflen, " ");
+	if (ret < 0)
+		return ret;
+	buf += ret;
+	buflen -= ret;
+
+	/* Dereferencing arguments */
+	if (arg->ref) {
+		depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf,
+							  &buflen, 1);
+		if (depth < 0)
+			return depth;
+	}
+
+	/* Print argument value */
+	ret = e_snprintf(buf, buflen, "%s", arg->value);
+	if (ret < 0)
+		return ret;
+	buf += ret;
+	buflen -= ret;
+
+	/* Closing */
+	while (depth--) {
+		ret = e_snprintf(buf, buflen, ")");
+		if (ret < 0)
+			return ret;
+		buf += ret;
+		buflen -= ret;
+	}
+
+	return buf - tmp;
+}
+
+char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev)
+{
+	struct kprobe_trace_point *tp = &tev->point;
 	char *buf;
 	int i, len, ret;
 
-	pp->probes[0] = buf = xzalloc(MAX_CMDLEN);
-	ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
-	if (ret <= 0)
+	buf = xzalloc(MAX_CMDLEN);
+	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu",
+			 tp->retprobe ? 'r' : 'p',
+			 tev->group, tev->event,
+			 tp->symbol, tp->offset);
+	if (len <= 0)
 		goto error;
-	len = ret;
 
-	for (i = 0; i < pp->nr_args; i++) {
-		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
-				 pp->args[i]);
+	for (i = 0; i < tev->nargs; i++) {
+		ret = synthesize_kprobe_trace_arg(&tev->args[i], buf + len,
+						  MAX_CMDLEN - len);
 		if (ret <= 0)
 			goto error;
 		len += ret;
 	}
-	pp->found = 1;
 
-	return pp->found;
+	return buf;
 error:
-	free(pp->probes[0]);
-	pp->probes[0] = NULL;
+	free(buf);
+	return NULL;
+}
 
-	return ret;
+void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
+				 struct perf_probe_event *pev)
+{
+	char buf[64];
+	int i;
+
+	pev->event = xstrdup(tev->event);
+	pev->group = xstrdup(tev->group);
+
+	/* Convert trace_point to probe_point */
+	pev->point.function = xstrdup(tev->point.symbol);
+	pev->point.offset = tev->point.offset;
+	pev->point.retprobe = tev->point.retprobe;
+
+	/* Convert trace_arg to probe_arg */
+	pev->nargs = tev->nargs;
+	pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
+	for (i = 0; i < tev->nargs; i++)
+		if (tev->args[i].name)
+			pev->args[i].name = xstrdup(tev->args[i].name);
+		else {
+			synthesize_kprobe_trace_arg(&tev->args[i], buf, 64);
+			pev->args[i].name = xstrdup(buf);
+		}
+}
+
+void clear_perf_probe_event(struct perf_probe_event *pev)
+{
+	struct perf_probe_point *pp = &pev->point;
+	int i;
+
+	if (pev->event)
+		free(pev->event);
+	if (pev->group)
+		free(pev->group);
+	if (pp->file)
+		free(pp->file);
+	if (pp->function)
+		free(pp->function);
+	if (pp->lazy_line)
+		free(pp->lazy_line);
+	for (i = 0; i < pev->nargs; i++)
+		if (pev->args[i].name)
+			free(pev->args[i].name);
+	if (pev->args)
+		free(pev->args);
+	memset(pev, 0, sizeof(*pev));
+}
+
+void clear_kprobe_trace_event(struct kprobe_trace_event *tev)
+{
+	struct kprobe_trace_arg_ref *ref, *next;
+	int i;
+
+	if (tev->event)
+		free(tev->event);
+	if (tev->group)
+		free(tev->group);
+	if (tev->point.symbol)
+		free(tev->point.symbol);
+	for (i = 0; i < tev->nargs; i++) {
+		if (tev->args[i].name)
+			free(tev->args[i].name);
+		if (tev->args[i].value)
+			free(tev->args[i].value);
+		ref = tev->args[i].ref;
+		while (ref) {
+			next = ref->next;
+			free(ref);
+			ref = next;
+		}
+	}
+	if (tev->args)
+		free(tev->args);
+	memset(tev, 0, sizeof(*tev));
 }
 
 static int open_kprobe_events(bool readwrite)
@@ -458,7 +609,7 @@ static int open_kprobe_events(bool readwrite)
 }
 
 /* Get raw string list of current kprobe_events */
-static struct strlist *get_trace_kprobe_event_rawlist(int fd)
+static struct strlist *get_kprobe_trace_command_rawlist(int fd)
 {
 	int ret, idx;
 	FILE *fp;
@@ -486,99 +637,82 @@ static struct strlist *get_trace_kprobe_event_rawlist(int fd)
 	return sl;
 }
 
-/* Free and zero clear probe_point */
-static void clear_probe_point(struct probe_point *pp)
-{
-	int i;
-
-	if (pp->event)
-		free(pp->event);
-	if (pp->group)
-		free(pp->group);
-	if (pp->function)
-		free(pp->function);
-	if (pp->file)
-		free(pp->file);
-	if (pp->lazy_line)
-		free(pp->lazy_line);
-	for (i = 0; i < pp->nr_args; i++)
-		free(pp->args[i]);
-	if (pp->args)
-		free(pp->args);
-	for (i = 0; i < pp->found; i++)
-		free(pp->probes[i]);
-	memset(pp, 0, sizeof(*pp));
-}
-
 /* Show an event */
-static void show_perf_probe_event(const char *event, const char *place,
-				  struct probe_point *pp)
+static void show_perf_probe_event(struct perf_probe_event *pev)
 {
 	int i, ret;
 	char buf[128];
+	char *place;
 
-	ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
+	/* Synthesize only event probe point */
+	place = synthesize_perf_probe_point(&pev->point);
+
+	ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
 	if (ret < 0)
 		die("Failed to copy event: %s", strerror(-ret));
 	printf("  %-40s (on %s", buf, place);
 
-	if (pp->nr_args > 0) {
+	if (pev->nargs > 0) {
 		printf(" with");
-		for (i = 0; i < pp->nr_args; i++)
-			printf(" %s", pp->args[i]);
+		for (i = 0; i < pev->nargs; i++)
+			printf(" %s", pev->args[i].name);
 	}
 	printf(")\n");
+	free(place);
 }
 
 /* List up current perf-probe events */
 void show_perf_probe_events(void)
 {
 	int fd;
-	struct probe_point pp;
+	struct kprobe_trace_event tev;
+	struct perf_probe_event pev;
 	struct strlist *rawlist;
 	struct str_node *ent;
 
 	setup_pager();
-	memset(&pp, 0, sizeof(pp));
+
+	memset(&tev, 0, sizeof(tev));
+	memset(&pev, 0, sizeof(pev));
 
 	fd = open_kprobe_events(false);
-	rawlist = get_trace_kprobe_event_rawlist(fd);
+	rawlist = get_kprobe_trace_command_rawlist(fd);
 	close(fd);
 
 	strlist__for_each(ent, rawlist) {
-		parse_trace_kprobe_event(ent->s, &pp);
-		/* Synthesize only event probe point */
-		synthesize_perf_probe_point(&pp);
+		parse_kprobe_trace_command(ent->s, &tev);
+		convert_to_perf_probe_event(&tev, &pev);
 		/* Show an event */
-		show_perf_probe_event(pp.event, pp.probes[0], &pp);
-		clear_probe_point(&pp);
+		show_perf_probe_event(&pev);
+		clear_perf_probe_event(&pev);
+		clear_kprobe_trace_event(&tev);
 	}
 
 	strlist__delete(rawlist);
 }
 
 /* Get current perf-probe event names */
-static struct strlist *get_perf_event_names(int fd, bool include_group)
+static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
 {
 	char buf[128];
 	struct strlist *sl, *rawlist;
 	struct str_node *ent;
-	struct probe_point pp;
+	struct kprobe_trace_event tev;
 
-	memset(&pp, 0, sizeof(pp));
-	rawlist = get_trace_kprobe_event_rawlist(fd);
+	memset(&tev, 0, sizeof(tev));
 
+	rawlist = get_kprobe_trace_command_rawlist(fd);
 	sl = strlist__new(true, NULL);
 	strlist__for_each(ent, rawlist) {
-		parse_trace_kprobe_event(ent->s, &pp);
+		parse_kprobe_trace_command(ent->s, &tev);
 		if (include_group) {
-			if (e_snprintf(buf, 128, "%s:%s", pp.group,
-				       pp.event) < 0)
+			if (e_snprintf(buf, 128, "%s:%s", tev.group,
+				       tev.event) < 0)
 				die("Failed to copy group:event name.");
 			strlist__add(sl, buf);
 		} else
-			strlist__add(sl, pp.event);
-		clear_probe_point(&pp);
+			strlist__add(sl, tev.event);
+		clear_kprobe_trace_event(&tev);
 	}
 
 	strlist__delete(rawlist);
@@ -586,9 +720,10 @@ static struct strlist *get_perf_event_names(int fd, bool include_group)
 	return sl;
 }
 
-static void write_trace_kprobe_event(int fd, const char *buf)
+static void write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev)
 {
 	int ret;
+	char *buf = synthesize_kprobe_trace_command(tev);
 
 	pr_debug("Writing event: %s\n", buf);
 	if (!probe_event_dry_run) {
@@ -596,6 +731,7 @@ static void write_trace_kprobe_event(int fd, const char *buf)
 		if (ret <= 0)
 			die("Failed to write event: %s", strerror(errno));
 	}
+	free(buf);
 }
 
 static void get_new_event_name(char *buf, size_t len, const char *base,
@@ -628,81 +764,83 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
 		die("Too many events are on the same function.");
 }
 
-static void __add_trace_kprobe_events(struct probe_point *probes,
-				      int nr_probes, bool force_add)
+static void __add_kprobe_trace_events(struct perf_probe_event *pev,
+				      struct kprobe_trace_event *tevs,
+				      int ntevs, bool allow_suffix)
 {
-	int i, j, fd;
-	struct probe_point *pp;
-	char buf[MAX_CMDLEN];
-	char event[64];
+	int i, fd;
+	struct kprobe_trace_event *tev;
+	char buf[64];
+	const char *event, *group;
 	struct strlist *namelist;
-	bool allow_suffix;
 
 	fd = open_kprobe_events(true);
 	/* Get current event names */
-	namelist = get_perf_event_names(fd, false);
-
-	for (j = 0; j < nr_probes; j++) {
-		pp = probes + j;
-		if (!pp->event)
-			pp->event = xstrdup(pp->function);
-		if (!pp->group)
-			pp->group = xstrdup(PERFPROBE_GROUP);
-		/* If force_add is true, suffix search is allowed */
-		allow_suffix = force_add;
-		for (i = 0; i < pp->found; i++) {
-			/* Get an unused new event name */
-			get_new_event_name(event, 64, pp->event, namelist,
-					   allow_suffix);
-			snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
-				 pp->retprobe ? 'r' : 'p',
-				 pp->group, event,
-				 pp->probes[i]);
-			write_trace_kprobe_event(fd, buf);
-			printf("Added new event:\n");
-			/* Get the first parameter (probe-point) */
-			sscanf(pp->probes[i], "%s", buf);
-			show_perf_probe_event(event, buf, pp);
-			/* Add added event name to namelist */
-			strlist__add(namelist, event);
-			/*
-			 * Probes after the first probe which comes from same
-			 * user input are always allowed to add suffix, because
-			 * there might be several addresses corresponding to
-			 * one code line.
-			 */
-			allow_suffix = true;
-		}
+	namelist = get_kprobe_trace_event_names(fd, false);
+
+	printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":");
+	for (i = 0; i < ntevs; i++) {
+		tev = &tevs[i];
+		if (pev->event)
+			event = pev->event;
+		else
+			if (pev->point.function)
+				event = pev->point.function;
+			else
+				event = tev->point.symbol;
+		if (pev->group)
+			group = pev->group;
+		else
+			group = PERFPROBE_GROUP;
+
+		/* Get an unused new event name */
+		get_new_event_name(buf, 64, event, namelist, allow_suffix);
+		event = buf;
+
+		tev->event = xstrdup(event);
+		tev->group = xstrdup(group);
+		write_kprobe_trace_event(fd, tev);
+		/* Add added event name to namelist */
+		strlist__add(namelist, event);
+
+		/* Trick here - save current event/group */
+		event = pev->event;
+		group = pev->group;
+		pev->event = tev->event;
+		pev->group = tev->group;
+		show_perf_probe_event(pev);
+		/* Trick here - restore current event/group */
+		pev->event = (char *)event;
+		pev->group = (char *)group;
+
+		/*
+		 * Probes after the first probe which comes from same
+		 * user input are always allowed to add suffix, because
+		 * there might be several addresses corresponding to
+		 * one code line.
+		 */
+		allow_suffix = true;
 	}
 	/* Show how to use the event. */
 	printf("\nYou can now use it on all perf tools, such as:\n\n");
-	printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
+	printf("\tperf record -e %s:%s -a sleep 1\n\n", tev->group, tev->event);
 
 	strlist__delete(namelist);
 	close(fd);
 }
 
-/* Currently just checking function name from symbol map */
-static void evaluate_probe_point(struct probe_point *pp)
+static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
+					  struct kprobe_trace_event **tevs)
 {
 	struct symbol *sym;
-	sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
-				       pp->function, NULL);
-	if (!sym)
-		die("Kernel symbol \'%s\' not found - probe not added.",
-		    pp->function);
-}
-
-void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
-			     bool force_add, bool need_dwarf)
-{
-	int i, ret;
-	struct probe_point *pp;
+	bool need_dwarf;
 #ifndef NO_DWARF_SUPPORT
 	int fd;
 #endif
-	/* Add probes */
-	init_vmlinux();
+	int ntevs = 0, i;
+	struct kprobe_trace_event *tev;
+
+	need_dwarf = perf_probe_event_need_dwarf(pev);
 
 	if (need_dwarf)
 #ifdef NO_DWARF_SUPPORT
@@ -721,57 +859,90 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
 	}
 
 	/* Searching probe points */
-	for (i = 0; i < nr_probes; i++) {
-		pp = &probes[i];
-		if (pp->found)
-			continue;
-
-		lseek(fd, SEEK_SET, 0);
-		ret = find_probe_point(fd, pp);
-		if (ret > 0)
-			continue;
-		if (ret == 0) {	/* No error but failed to find probe point. */
-			synthesize_perf_probe_point(pp);
-			die("Probe point '%s' not found. - probe not added.",
-			    pp->probes[0]);
-		}
-		/* Error path */
-		if (need_dwarf) {
-			if (ret == -ENOENT)
-				pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
-			die("Could not analyze debuginfo.");
-		}
-		pr_debug("An error occurred in debuginfo analysis."
-			 " Try to use symbols.\n");
-		break;
+	ntevs = find_kprobe_trace_events(fd, pev, tevs);
+
+	if (ntevs > 0)	/* Found */
+		goto found;
+
+	if (ntevs == 0)	/* No error but failed to find probe point. */
+		die("Probe point '%s' not found. - probe not added.",
+		    synthesize_perf_probe_point(&pev->point));
+
+	/* Error path */
+	if (need_dwarf) {
+		if (ntevs == -ENOENT)
+			pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
+		die("Could not analyze debuginfo.");
 	}
-	close(fd);
+	pr_debug("An error occurred in debuginfo analysis."
+		 " Try to use symbols.\n");
 
 end_dwarf:
 #endif /* !NO_DWARF_SUPPORT */
 
-	/* Synthesize probes without dwarf */
-	for (i = 0; i < nr_probes; i++) {
-		pp = &probes[i];
-		if (pp->found)	/* This probe is already found. */
-			continue;
+	/* Allocate trace event buffer */
+	ntevs = 1;
+	tev = *tevs = xzalloc(sizeof(struct kprobe_trace_event));
+
+	/* Copy parameters */
+	tev->point.symbol = xstrdup(pev->point.function);
+	tev->point.offset = pev->point.offset;
+	tev->nargs = pev->nargs;
+	if (tev->nargs) {
+		tev->args = xzalloc(sizeof(struct kprobe_trace_arg)
+				    * tev->nargs);
+		for (i = 0; i < tev->nargs; i++)
+			tev->args[i].value = xstrdup(pev->args[i].name);
+	}
+
+	/* Currently just checking function name from symbol map */
+	sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
+				       tev->point.symbol, NULL);
+	if (!sym)
+		die("Kernel symbol \'%s\' not found - probe not added.",
+		    tev->point.symbol);
+found:
+	close(fd);
+	return ntevs;
+}
+
+struct __event_package {
+	struct perf_probe_event		*pev;
+	struct kprobe_trace_event	*tevs;
+	int				ntevs;
+};
 
-		evaluate_probe_point(pp);
-		ret = synthesize_trace_kprobe_event(pp);
-		if (ret == -E2BIG)
-			die("probe point definition becomes too long.");
-		else if (ret < 0)
-			die("Failed to synthesize a probe point.");
+void add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
+			   bool force_add)
+{
+	int i;
+	struct __event_package *pkgs;
+
+	pkgs = xzalloc(sizeof(struct __event_package) * npevs);
+
+	/* Init vmlinux path */
+	init_vmlinux();
+
+	/* Loop 1: convert all events */
+	for (i = 0; i < npevs; i++) {
+		pkgs[i].pev = &pevs[i];
+		/* Convert with or without debuginfo */
+		pkgs[i].ntevs = convert_to_kprobe_trace_events(pkgs[i].pev,
+							       &pkgs[i].tevs);
 	}
 
-	/* Settng up probe points */
-	__add_trace_kprobe_events(probes, nr_probes, force_add);
+	/* Loop 2: add all events */
+	for (i = 0; i < npevs; i++)
+		__add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs,
+					  pkgs[i].ntevs, force_add);
+	/* TODO: cleanup all trace events? */
 }
 
 static void __del_trace_kprobe_event(int fd, struct str_node *ent)
 {
 	char *p;
 	char buf[128];
+	int ret;
 
 	/* Convert from perf-probe event to trace-kprobe event */
 	if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
@@ -781,7 +952,10 @@ static void __del_trace_kprobe_event(int fd, struct str_node *ent)
 		die("Internal error: %s should have ':' but not.", ent->s);
 	*p = '/';
 
-	write_trace_kprobe_event(fd, buf);
+	pr_debug("Writing event: %s\n", buf);
+	ret = write(fd, buf, strlen(buf));
+	if (ret <= 0)
+		die("Failed to write event: %s", strerror(errno));
 	printf("Remove event: %s\n", ent->s);
 }
 
@@ -814,7 +988,7 @@ static void del_trace_kprobe_event(int fd, const char *group,
 		pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
 }
 
-void del_trace_kprobe_events(struct strlist *dellist)
+void del_perf_probe_events(struct strlist *dellist)
 {
 	int fd;
 	const char *group, *event;
@@ -824,7 +998,7 @@ void del_trace_kprobe_events(struct strlist *dellist)
 
 	fd = open_kprobe_events(true);
 	/* Get current event names */
-	namelist = get_perf_event_names(fd, true);
+	namelist = get_kprobe_trace_event_names(fd, true);
 
 	strlist__for_each(ent, dellist) {
 		str = xstrdup(ent->s);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 703b887..2a2f0a2 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -2,24 +2,113 @@
 #define _PROBE_EVENT_H
 
 #include <stdbool.h>
-#include "probe-finder.h"
 #include "strlist.h"
 
 extern bool probe_event_dry_run;
 
-extern void parse_line_range_desc(const char *arg, struct line_range *lr);
-extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
-				   bool *need_dwarf);
-extern int synthesize_perf_probe_point(struct probe_point *pp);
-extern int synthesize_perf_probe_event(struct probe_point *pp);
-extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
-extern int synthesize_trace_kprobe_event(struct probe_point *pp);
-extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
-				    bool force_add, bool need_dwarf);
-extern void del_trace_kprobe_events(struct strlist *dellist);
+/* kprobe-tracer tracing point */
+struct kprobe_trace_point {
+	char		*symbol;	/* Base symbol */
+	unsigned long	offset;		/* Offset from symbol */
+	bool		retprobe;	/* Return probe flag */
+};
+
+/* kprobe-tracer tracing argument referencing offset */
+struct kprobe_trace_arg_ref {
+	struct kprobe_trace_arg_ref	*next;	/* Next reference */
+	long				offset;	/* Offset value */
+};
+
+/* kprobe-tracer tracing argument */
+struct kprobe_trace_arg {
+	char				*name;	/* Argument name */
+	char				*value;	/* Base value */
+	struct kprobe_trace_arg_ref	*ref;	/* Referencing offset */
+};
+
+/* kprobe-tracer tracing event (point + arg) */
+struct kprobe_trace_event {
+	char				*event;	/* Event name */
+	char				*group;	/* Group name */
+	struct kprobe_trace_point	point;	/* Trace point */
+	int				nargs;	/* Number of args */
+	struct kprobe_trace_arg		*args;	/* Arguments */
+};
+
+/* Perf probe probing point */
+struct perf_probe_point {
+	char		*file;		/* File path */
+	char		*function;	/* Function name */
+	int		line;		/* Line number */
+	char		*lazy_line;	/* Lazy matching pattern */
+	unsigned long	offset;		/* Offset from function entry */
+	bool		retprobe;	/* Return probe flag */
+};
+
+/* Perf probe probing argument */
+struct perf_probe_arg {
+	char		*name;		/* Argument name */
+};
+
+/* Perf probe probing event (point + arg) */
+struct perf_probe_event {
+	char			*event;	/* Event name */
+	char			*group;	/* Group name */
+	struct perf_probe_point	point;	/* Probe point */
+	int			nargs;	/* Number of arguments */
+	struct perf_probe_arg	*args;	/* Arguments */
+};
+
+
+/* Line number container */
+struct line_node {
+	struct list_head	list;
+	unsigned int		line;
+};
+
+/* Line range */
+struct line_range {
+	char			*file;		/* File name */
+	char			*function;	/* Function name */
+	unsigned int		start;		/* Start line number */
+	unsigned int		end;		/* End line number */
+	int			offset;		/* Start line offset */
+	char			*path;		/* Real path name */
+	struct list_head	line_list;	/* Visible lines */
+};
+
+/* Command string to events */
+extern void parse_perf_probe_command(const char *cmd,
+				     struct perf_probe_event *pev);
+extern void parse_kprobe_trace_command(const char *cmd,
+				       struct kprobe_trace_event *tev);
+
+/* Events to command string */
+extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
+extern char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev);
+
+/* Check the perf_probe_event needs debuginfo */
+extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
+
+/* Convert from kprobe_trace_event to perf_probe_event */
+extern void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
+					struct perf_probe_event *pev);
+
+/* Release event contents */
+extern void clear_perf_probe_event(struct perf_probe_event *pev);
+extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev);
+
+/* Command string to line-range */
+extern void parse_line_range_desc(const char *cmd, struct line_range *lr);
+
+
+extern void add_perf_probe_events(struct perf_probe_event *pevs, int ntevs,
+				  bool force_add);
+extern void del_perf_probe_events(struct strlist *dellist);
 extern void show_perf_probe_events(void);
 extern void show_line_range(struct line_range *lr);
 
+
 /* Maximum index number of event-name postfix */
 #define MAX_EVENT_INDEX	1024
 
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 3942e14..251b4c4 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -319,19 +319,20 @@ static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
  */
 
 /* Show a location */
-static void show_location(Dwarf_Op *op, struct probe_finder *pf)
+static void convert_location(Dwarf_Op *op, struct probe_finder *pf)
 {
 	unsigned int regn;
 	Dwarf_Word offs = 0;
-	int deref = 0, ret;
+	bool ref = false;
 	const char *regs;
+	struct kprobe_trace_arg *tvar = pf->tvar;
 
 	/* TODO: support CFA */
 	/* If this is based on frame buffer, set the offset */
 	if (op->atom == DW_OP_fbreg) {
 		if (pf->fb_ops == NULL)
 			die("The attribute of frame base is not supported.\n");
-		deref = 1;
+		ref = true;
 		offs = op->number;
 		op = &pf->fb_ops[0];
 	}
@@ -339,13 +340,13 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf)
 	if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
 		regn = op->atom - DW_OP_breg0;
 		offs += op->number;
-		deref = 1;
+		ref = true;
 	} else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
 		regn = op->atom - DW_OP_reg0;
 	} else if (op->atom == DW_OP_bregx) {
 		regn = op->number;
 		offs += op->number2;
-		deref = 1;
+		ref = true;
 	} else if (op->atom == DW_OP_regx) {
 		regn = op->number;
 	} else
@@ -355,17 +356,15 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf)
 	if (!regs)
 		die("%u exceeds max register number.", regn);
 
-	if (deref)
-		ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)",
-			       pf->var, (intmax_t)offs, regs);
-	else
-		ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
-	DIE_IF(ret < 0);
-	DIE_IF(ret >= pf->len);
+	tvar->value = xstrdup(regs);
+	if (ref) {
+		tvar->ref = xzalloc(sizeof(struct kprobe_trace_arg_ref));
+		tvar->ref->offset = (long)offs;
+	}
 }
 
 /* Show a variables in kprobe event format */
-static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
+static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 {
 	Dwarf_Attribute attr;
 	Dwarf_Op *expr;
@@ -379,50 +378,51 @@ static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 	if (ret <= 0 || nexpr == 0)
 		goto error;
 
-	show_location(expr, pf);
+	convert_location(expr, pf);
 	/* *expr will be cached in libdw. Don't free it. */
 	return ;
 error:
 	/* TODO: Support const_value */
 	die("Failed to find the location of %s at this address.\n"
-	    " Perhaps, it has been optimized out.", pf->var);
+	    " Perhaps, it has been optimized out.", pf->pvar->name);
 }
 
 /* Find a variable in a subprogram die */
 static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
-	int ret;
 	Dwarf_Die vr_die;
 
 	/* TODO: Support struct members and arrays */
-	if (!is_c_varname(pf->var)) {
-		/* Output raw parameters */
-		ret = snprintf(pf->buf, pf->len, " %s", pf->var);
-		DIE_IF(ret < 0);
-		DIE_IF(ret >= pf->len);
-		return ;
+	if (!is_c_varname(pf->pvar->name)) {
+		/* Copy raw parameters */
+		pf->tvar->value = xstrdup(pf->pvar->name);
+	} else {
+		pf->tvar->name = xstrdup(pf->pvar->name);
+		pr_debug("Searching '%s' variable in context.\n",
+			 pf->pvar->name);
+		/* Search child die for local variables and parameters. */
+		if (!die_find_variable(sp_die, pf->pvar->name, &vr_die))
+			die("Failed to find '%s' in this function.",
+			    pf->pvar->name);
+		convert_variable(&vr_die, pf);
 	}
-
-	pr_debug("Searching '%s' variable in context.\n", pf->var);
-	/* Search child die for local variables and parameters. */
-	if (!die_find_variable(sp_die, pf->var, &vr_die))
-		die("Failed to find '%s' in this function.", pf->var);
-
-	show_variable(&vr_die, pf);
 }
 
 /* Show a probe point to output buffer */
-static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
+static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
-	struct probe_point *pp = pf->pp;
+	struct kprobe_trace_event *tev;
 	Dwarf_Addr eaddr;
 	Dwarf_Die die_mem;
 	const char *name;
-	char tmp[MAX_PROBE_BUFFER];
-	int ret, i, len;
+	int ret, i;
 	Dwarf_Attribute fb_attr;
 	size_t nops;
 
+	if (pf->ntevs == MAX_PROBES)
+		die("Too many( > %d) probe point found.\n", MAX_PROBES);
+	tev = &pf->tevs[pf->ntevs++];
+
 	/* If no real subprogram, find a real one */
 	if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
 		sp_die = die_find_real_subprogram(&pf->cu_die,
@@ -431,31 +431,18 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 			die("Probe point is not found in subprograms.");
 	}
 
-	/* Output name of probe point */
+	/* Copy the name of probe point */
 	name = dwarf_diename(sp_die);
 	if (name) {
 		dwarf_entrypc(sp_die, &eaddr);
-		ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name,
-				(unsigned long)(pf->addr - eaddr));
-		/* Copy the function name if possible */
-		if (!pp->function) {
-			pp->function = xstrdup(name);
-			pp->offset = (size_t)(pf->addr - eaddr);
-		}
-	} else {
+		tev->point.symbol = xstrdup(name);
+		tev->point.offset = (unsigned long)(pf->addr - eaddr);
+	} else
 		/* This function has no name. */
-		ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx",
-			       (uintmax_t)pf->addr);
-		if (!pp->function) {
-			/* TODO: Use _stext */
-			pp->function = xstrdup("");
-			pp->offset = (size_t)pf->addr;
-		}
-	}
-	DIE_IF(ret < 0);
-	DIE_IF(ret >= MAX_PROBE_BUFFER);
-	len = ret;
-	pr_debug("Probe point found: %s\n", tmp);
+		tev->point.offset = (unsigned long)pf->addr;
+
+	pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
+		 tev->point.offset);
 
 	/* Get the frame base attribute/ops */
 	dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
@@ -465,22 +452,16 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 
 	/* Find each argument */
 	/* TODO: use dwarf_cfi_addrframe */
-	for (i = 0; i < pp->nr_args; i++) {
-		pf->var = pp->args[i];
-		pf->buf = &tmp[len];
-		pf->len = MAX_PROBE_BUFFER - len;
+	tev->nargs = pf->pev->nargs;
+	tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
+	for (i = 0; i < pf->pev->nargs; i++) {
+		pf->pvar = &pf->pev->args[i];
+		pf->tvar = &tev->args[i];
 		find_variable(sp_die, pf);
-		len += strlen(pf->buf);
 	}
 
 	/* *pf->fb_ops will be cached in libdw. Don't free it. */
 	pf->fb_ops = NULL;
-
-	if (pp->found == MAX_PROBES)
-		die("Too many( > %d) probe point found.\n", MAX_PROBES);
-
-	pp->probes[pp->found] = xstrdup(tmp);
-	pp->found++;
 }
 
 /* Find probe point from its line number */
@@ -512,7 +493,7 @@ static void find_probe_point_by_line(struct probe_finder *pf)
 			 (int)i, lineno, (uintmax_t)addr);
 		pf->addr = addr;
 
-		show_probe_point(NULL, pf);
+		convert_probe_point(NULL, pf);
 		/* Continuing, because target line might be inlined. */
 	}
 }
@@ -563,7 +544,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 	if (list_empty(&pf->lcache)) {
 		/* Matching lazy line pattern */
 		ret = find_lazy_match_lines(&pf->lcache, pf->fname,
-					    pf->pp->lazy_line);
+					    pf->pev->point.lazy_line);
 		if (ret <= 0)
 			die("No matched lines found in %s.", pf->fname);
 	}
@@ -596,7 +577,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 			 (int)i, lineno, (unsigned long long)addr);
 		pf->addr = addr;
 
-		show_probe_point(sp_die, pf);
+		convert_probe_point(sp_die, pf);
 		/* Continuing, because target line might be inlined. */
 	}
 	/* TODO: deallocate lines, but how? */
@@ -605,7 +586,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
 {
 	struct probe_finder *pf = (struct probe_finder *)data;
-	struct probe_point *pp = pf->pp;
+	struct perf_probe_point *pp = &pf->pev->point;
 
 	if (pp->lazy_line)
 		find_probe_point_lazy(in_die, pf);
@@ -616,7 +597,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
 		pr_debug("found inline addr: 0x%jx\n",
 			 (uintmax_t)pf->addr);
 
-		show_probe_point(in_die, pf);
+		convert_probe_point(in_die, pf);
 	}
 
 	return DWARF_CB_OK;
@@ -626,7 +607,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
 static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
 {
 	struct probe_finder *pf = (struct probe_finder *)data;
-	struct probe_point *pp = pf->pp;
+	struct perf_probe_point *pp = &pf->pev->point;
 
 	/* Check tag and diename */
 	if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
@@ -646,7 +627,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
 			pf->addr = die_get_entrypc(sp_die);
 			pf->addr += pp->offset;
 			/* TODO: Check the address in this function */
-			show_probe_point(sp_die, pf);
+			convert_probe_point(sp_die, pf);
 		}
 	} else
 		/* Inlined function: search instances */
@@ -660,20 +641,25 @@ static void find_probe_point_by_func(struct probe_finder *pf)
 	dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
 }
 
-/* Find a probe point */
-int find_probe_point(int fd, struct probe_point *pp)
+/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
+int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
+			     struct kprobe_trace_event **tevs)
 {
-	struct probe_finder pf = {.pp = pp};
+	struct probe_finder pf = {.pev = pev};
+	struct perf_probe_point *pp = &pev->point;
 	Dwarf_Off off, noff;
 	size_t cuhl;
 	Dwarf_Die *diep;
 	Dwarf *dbg;
 
+	pf.tevs = xzalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES);
+	*tevs = pf.tevs;
+	pf.ntevs = 0;
+
 	dbg = dwarf_begin(fd, DWARF_C_READ);
 	if (!dbg)
 		return -ENOENT;
 
-	pp->found = 0;
 	off = 0;
 	line_list__init(&pf.lcache);
 	/* Loop on CUs (Compilation Unit) */
@@ -704,7 +690,7 @@ int find_probe_point(int fd, struct probe_point *pp)
 	line_list__free(&pf.lcache);
 	dwarf_end(dbg);
 
-	return pp->found;
+	return pf.ntevs;
 }
 
 /* Find line range from its line number */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 21f7354..4949526 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include "util.h"
+#include "probe-event.h"
 
 #define MAX_PATH_LEN		 256
 #define MAX_PROBE_BUFFER	1024
@@ -14,67 +15,32 @@ static inline int is_c_varname(const char *name)
 	return isalpha(name[0]) || name[0] == '_';
 }
 
-struct probe_point {
-	char			*event;			/* Event name */
-	char			*group;			/* Event group */
-
-	/* Inputs */
-	char			*file;			/* File name */
-	int			line;			/* Line number */
-	char			*lazy_line;		/* Lazy line pattern */
-
-	char			*function;		/* Function name */
-	int			offset;			/* Offset bytes */
-
-	int			nr_args;		/* Number of arguments */
-	char			**args;			/* Arguments */
-
-	int			retprobe;		/* Return probe */
-
-	/* Output */
-	int			found;			/* Number of found probe points */
-	char			*probes[MAX_PROBES];	/* Output buffers (will be allocated)*/
-};
-
-/* Line number container */
-struct line_node {
-	struct list_head	list;
-	unsigned int		line;
-};
-
-/* Line range */
-struct line_range {
-	char			*file;			/* File name */
-	char			*function;		/* Function name */
-	unsigned int		start;			/* Start line number */
-	unsigned int		end;			/* End line number */
-	int			offset;			/* Start line offset */
-	char			*path;			/* Real path name */
-	struct list_head	line_list;		/* Visible lines */
-};
-
 #ifndef NO_DWARF_SUPPORT
-extern int find_probe_point(int fd, struct probe_point *pp);
+/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
+extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
+				    struct kprobe_trace_event **tevs);
+
 extern int find_line_range(int fd, struct line_range *lr);
 
 #include <dwarf.h>
 #include <libdw.h>
 
 struct probe_finder {
-	struct probe_point	*pp;		/* Target probe point */
+	struct perf_probe_event	*pev;		/* Target probe event */
+	int			ntevs;		/* number of trace events */
+	struct kprobe_trace_event *tevs;	/* Result trace events */
 
 	/* For function searching */
 	Dwarf_Addr		addr;		/* Address */
-	const char		*fname;		/* File name */
+	const char		*fname;		/* Real file name */
 	int			lno;		/* Line number */
 	Dwarf_Die		cu_die;		/* Current CU */
+	struct list_head	lcache;		/* Line cache for lazy match */
 
 	/* For variable searching */
 	Dwarf_Op		*fb_ops;	/* Frame base attribute */
-	const char		*var;		/* Current variable name */
-	char			*buf;		/* Current output buffer */
-	int			len;		/* Length of output buffer */
-	struct list_head	lcache;		/* Line cache for lazy match */
+	struct perf_probe_arg	*pvar;		/* Current target variable */
+	struct kprobe_trace_arg	*tvar;		/* Current result variable */
 };
 
 struct line_finder {

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

* [tip:perf/core] perf probe: List probes with line number and file name
  2010-03-16 22:06 ` [PATCH -tip 09/10] perf probe: List probes with line number and file name Masami Hiramatsu
@ 2010-03-17 11:29   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-03-17 11:29 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, paulus, acme, hpa, mingo, a.p.zijlstra, efault,
	dle-develop, fweisbec, tglx, mhiramat, mingo, systemtap

Commit-ID:  fb1587d869a399554220e166d4b90b581a8ade01
Gitweb:     http://git.kernel.org/tip/fb1587d869a399554220e166d4b90b581a8ade01
Author:     Masami Hiramatsu <mhiramat@redhat.com>
AuthorDate: Tue, 16 Mar 2010 18:06:19 -0400
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Wed, 17 Mar 2010 11:32:32 +0100

perf probe: List probes with line number and file name

Improve --list to show current exist probes with line number and
file name. This enables user easily to check which line is
already probed.

for example:

 ./perf probe --list
 probe:vfs_read       (on vfs_read:8@linux-2.6-tip/fs/read_write.c)

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220619.32050.48702.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 tools/perf/util/probe-event.c  |   57 ++++++++++++++++++++++++--------
 tools/perf/util/probe-finder.c |   70 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/probe-finder.h |    4 ++
 3 files changed, 117 insertions(+), 14 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index b44ddfb..4e3c1ae 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -70,7 +70,6 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 	return ret;
 }
 
-
 static struct map_groups kmap_groups;
 static struct map *kmaps[MAP__NR_TYPES];
 
@@ -357,27 +356,39 @@ void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
 /* Compose only probe point (not argument) */
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 {
-	char *buf;
-	char offs[64] = "", line[64] = "";
-	int ret;
+	char *buf, *tmp;
+	char offs[32] = "", line[32] = "", file[32] = "";
+	int ret, len;
 
 	buf = xzalloc(MAX_CMDLEN);
 	if (pp->offset) {
-		ret = e_snprintf(offs, 64, "+%lu", pp->offset);
+		ret = e_snprintf(offs, 32, "+%lu", pp->offset);
 		if (ret <= 0)
 			goto error;
 	}
 	if (pp->line) {
-		ret = e_snprintf(line, 64, ":%d", pp->line);
+		ret = e_snprintf(line, 32, ":%d", pp->line);
+		if (ret <= 0)
+			goto error;
+	}
+	if (pp->file) {
+		len = strlen(pp->file) - 32;
+		if (len < 0)
+			len = 0;
+		tmp = strchr(pp->file + len, '/');
+		if (!tmp)
+			tmp = pp->file + len - 1;
+		ret = e_snprintf(file, 32, "@%s", tmp + 1);
 		if (ret <= 0)
 			goto error;
 	}
 
 	if (pp->function)
-		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
-				 offs, pp->retprobe ? "%return" : "", line);
+		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
+				 offs, pp->retprobe ? "%return" : "", line,
+				 file);
 	else
-		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
+		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
 	if (ret <= 0)
 		goto error;
 
@@ -511,15 +522,32 @@ void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
 {
 	char buf[64];
 	int i;
+#ifndef NO_DWARF_SUPPORT
+	struct symbol *sym;
+	int fd, ret = 0;
 
-	pev->event = xstrdup(tev->event);
-	pev->group = xstrdup(tev->group);
-
+	sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
+				       tev->point.symbol, NULL);
+	if (sym) {
+		fd = open_vmlinux();
+		ret = find_perf_probe_point(fd, sym->start + tev->point.offset,
+					    &pev->point);
+		close(fd);
+	}
+	if (ret <= 0) {
+		pev->point.function = xstrdup(tev->point.symbol);
+		pev->point.offset = tev->point.offset;
+	}
+#else
 	/* Convert trace_point to probe_point */
 	pev->point.function = xstrdup(tev->point.symbol);
 	pev->point.offset = tev->point.offset;
+#endif
 	pev->point.retprobe = tev->point.retprobe;
 
+	pev->event = xstrdup(tev->event);
+	pev->group = xstrdup(tev->group);
+
 	/* Convert trace_arg to probe_arg */
 	pev->nargs = tev->nargs;
 	pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
@@ -650,7 +678,7 @@ static void show_perf_probe_event(struct perf_probe_event *pev)
 	ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
 	if (ret < 0)
 		die("Failed to copy event: %s", strerror(-ret));
-	printf("  %-40s (on %s", buf, place);
+	printf("  %-20s (on %s", buf, place);
 
 	if (pev->nargs > 0) {
 		printf(" with");
@@ -671,6 +699,7 @@ void show_perf_probe_events(void)
 	struct str_node *ent;
 
 	setup_pager();
+	init_vmlinux();
 
 	memset(&tev, 0, sizeof(tev));
 	memset(&pev, 0, sizeof(pev));
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 251b4c4..e02b607 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -693,6 +693,76 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
 	return pf.ntevs;
 }
 
+/* Reverse search */
+int find_perf_probe_point(int fd, unsigned long addr,
+			  struct perf_probe_point *ppt)
+{
+	Dwarf_Die cudie, spdie, indie;
+	Dwarf *dbg;
+	Dwarf_Line *line;
+	Dwarf_Addr laddr, eaddr;
+	const char *tmp;
+	int lineno, ret = 0;
+
+	dbg = dwarf_begin(fd, DWARF_C_READ);
+	if (!dbg)
+		return -ENOENT;
+
+	/* Find cu die */
+	if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie))
+		return -EINVAL;
+
+	/* Find a corresponding line */
+	line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
+	if (line) {
+		dwarf_lineaddr(line, &laddr);
+		if ((Dwarf_Addr)addr == laddr) {
+			dwarf_lineno(line, &lineno);
+			ppt->line = lineno;
+
+			tmp = dwarf_linesrc(line, NULL, NULL);
+			DIE_IF(!tmp);
+			ppt->file = xstrdup(tmp);
+			ret = 1;
+		}
+	}
+
+	/* Find a corresponding function */
+	if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
+		tmp = dwarf_diename(&spdie);
+		if (!tmp)
+			goto end;
+
+		dwarf_entrypc(&spdie, &eaddr);
+		if (!lineno) {
+			/* We don't have a line number, let's use offset */
+			ppt->function = xstrdup(tmp);
+			ppt->offset = addr - (unsigned long)eaddr;
+			ret = 1;
+			goto end;
+		}
+		if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, &indie)) {
+			/* addr in an inline function */
+			tmp = dwarf_diename(&indie);
+			if (!tmp)
+				goto end;
+			dwarf_decl_line(&indie, &lineno);
+		} else {
+			if (eaddr == addr)	/* No offset: function entry */
+				lineno = ppt->line;
+			else
+				dwarf_decl_line(&spdie, &lineno);
+		}
+		ppt->function = xstrdup(tmp);
+		ppt->line -= lineno;	/* Make a relative line number */
+	}
+
+end:
+	dwarf_end(dbg);
+	return ret;
+}
+
+
 /* Find line range from its line number */
 static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 {
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 4949526..2f2307d 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -20,6 +20,10 @@ static inline int is_c_varname(const char *name)
 extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
 				    struct kprobe_trace_event **tevs);
 
+/* Find a perf_probe_point from debuginfo */
+extern int find_perf_probe_point(int fd, unsigned long addr,
+				 struct perf_probe_point *ppt);
+
 extern int find_line_range(int fd, struct line_range *lr);
 
 #include <dwarf.h>

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

* [tip:perf/core] perf probe: Add data structure member access support
  2010-03-16 22:06 ` [PATCH -tip 10/10] perf probe: Accessing members in data structures Masami Hiramatsu
  2010-03-17 10:25   ` Mark Wielaard
@ 2010-03-17 11:30   ` tip-bot for Masami Hiramatsu
  1 sibling, 0 replies; 32+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-03-17 11:30 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, paulus, acme, hpa, mingo, a.p.zijlstra, efault,
	dle-develop, fweisbec, tglx, mhiramat, mingo, systemtap

Commit-ID:  7df2f32956cf0f1a45df38cd0e0fe0c3467580e8
Gitweb:     http://git.kernel.org/tip/7df2f32956cf0f1a45df38cd0e0fe0c3467580e8
Author:     Masami Hiramatsu <mhiramat@redhat.com>
AuthorDate: Tue, 16 Mar 2010 18:06:26 -0400
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Wed, 17 Mar 2010 12:11:15 +0100

perf probe: Add data structure member access support

Support accessing members in the data structures. With this,
perf-probe accepts data-structure members(IOW, it now accepts
dot '.' and arrow '->' operators) as probe arguemnts.

e.g.

 ./perf probe --add 'schedule:44 rq->curr'

 ./perf probe --add 'vfs_read file->f_op->read file->f_path.dentry'

Note that '>' can be interpreted as redirection in command-line.

Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220626.32050.57552.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 tools/perf/util/probe-event.c  |   90 ++++++++++++++++++++++++++++++++--
 tools/perf/util/probe-event.h  |   12 ++++-
 tools/perf/util/probe-finder.c |  105 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 201 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 4e3c1ae..64dea6c 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -262,6 +262,49 @@ static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
 		 pp->lazy_line);
 }
 
+/* Parse perf-probe event argument */
+static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg)
+{
+	const char *tmp;
+	struct perf_probe_arg_field **fieldp;
+
+	pr_debug("parsing arg: %s into ", str);
+
+	tmp = strpbrk(str, "-.");
+	if (!is_c_varname(str) || !tmp) {
+		/* A variable, register, symbol or special value */
+		arg->name = xstrdup(str);
+		pr_debug("%s\n", arg->name);
+		return;
+	}
+
+	/* Structure fields */
+	arg->name = xstrndup(str, tmp - str);
+	pr_debug("%s, ", arg->name);
+	fieldp = &arg->field;
+
+	do {
+		*fieldp = xzalloc(sizeof(struct perf_probe_arg_field));
+		if (*tmp == '.') {
+			str = tmp + 1;
+			(*fieldp)->ref = false;
+		} else if (tmp[1] == '>') {
+			str = tmp + 2;
+			(*fieldp)->ref = true;
+		} else
+			semantic_error("Argument parse error: %s", str);
+
+		tmp = strpbrk(str, "-.");
+		if (tmp) {
+			(*fieldp)->name = xstrndup(str, tmp - str);
+			pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
+			fieldp = &(*fieldp)->next;
+		}
+	} while (tmp);
+	(*fieldp)->name = xstrdup(str);
+	pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
+}
+
 /* Parse perf-probe event command */
 void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
 {
@@ -281,7 +324,7 @@ void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
 	pev->nargs = argc - 1;
 	pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
 	for (i = 0; i < pev->nargs; i++) {
-		pev->args[i].name = xstrdup(argv[i + 1]);
+		parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
 		if (is_c_varname(pev->args[i].name) && pev->point.retprobe)
 			semantic_error("You can't specify local variable for"
 				       " kretprobe");
@@ -353,6 +396,33 @@ void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
 	argv_free(argv);
 }
 
+/* Compose only probe arg */
+int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
+{
+	struct perf_probe_arg_field *field = pa->field;
+	int ret;
+	char *tmp = buf;
+
+	ret = e_snprintf(tmp, len, "%s", pa->name);
+	if (ret <= 0)
+		goto error;
+	tmp += ret;
+	len -= ret;
+
+	while (field) {
+		ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".",
+				 field->name);
+		if (ret <= 0)
+			goto error;
+		tmp += ret;
+		len -= ret;
+		field = field->next;
+	}
+	return tmp - buf;
+error:
+	die("Failed to synthesize perf probe argument: %s", strerror(-ret));
+}
+
 /* Compose only probe point (not argument) */
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
 {
@@ -563,6 +633,7 @@ void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
 void clear_perf_probe_event(struct perf_probe_event *pev)
 {
 	struct perf_probe_point *pp = &pev->point;
+	struct perf_probe_arg_field *field, *next;
 	int i;
 
 	if (pev->event)
@@ -575,9 +646,18 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
 		free(pp->function);
 	if (pp->lazy_line)
 		free(pp->lazy_line);
-	for (i = 0; i < pev->nargs; i++)
+	for (i = 0; i < pev->nargs; i++) {
 		if (pev->args[i].name)
 			free(pev->args[i].name);
+		field = pev->args[i].field;
+		while (field) {
+			next = field->next;
+			if (field->name)
+				free(field->name);
+			free(field);
+			field = next;
+		}
+	}
 	if (pev->args)
 		free(pev->args);
 	memset(pev, 0, sizeof(*pev));
@@ -682,8 +762,10 @@ static void show_perf_probe_event(struct perf_probe_event *pev)
 
 	if (pev->nargs > 0) {
 		printf(" with");
-		for (i = 0; i < pev->nargs; i++)
-			printf(" %s", pev->args[i].name);
+		for (i = 0; i < pev->nargs; i++) {
+			synthesize_perf_probe_arg(&pev->args[i], buf, 128);
+			printf(" %s", buf);
+		}
 	}
 	printf(")\n");
 	free(place);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 2a2f0a2..cd308b0 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -45,9 +45,17 @@ struct perf_probe_point {
 	bool		retprobe;	/* Return probe flag */
 };
 
+/* Perf probe probing argument field chain */
+struct perf_probe_arg_field {
+	struct perf_probe_arg_field	*next;	/* Next field */
+	char				*name;	/* Name of the field */
+	bool				ref;	/* Referencing flag */
+};
+
 /* Perf probe probing argument */
 struct perf_probe_arg {
-	char		*name;		/* Argument name */
+	char				*name;	/* Argument name */
+	struct perf_probe_arg_field	*field;	/* Structure fields */
 };
 
 /* Perf probe probing event (point + arg) */
@@ -86,6 +94,8 @@ extern void parse_kprobe_trace_command(const char *cmd,
 /* Events to command string */
 extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
 extern char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev);
+extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf,
+				     size_t len);
 
 /* Check the perf_probe_event needs debuginfo */
 extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index e02b607..db52ec2 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -206,6 +206,28 @@ static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
 	return epc;
 }
 
+/* Get type die, but skip qualifiers and typedef */
+static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+{
+	Dwarf_Attribute attr;
+	int tag;
+
+	do {
+		if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL ||
+		    dwarf_formref_die(&attr, die_mem) == NULL)
+			return NULL;
+
+		tag = dwarf_tag(die_mem);
+		vr_die = die_mem;
+	} while (tag == DW_TAG_const_type ||
+		 tag == DW_TAG_restrict_type ||
+		 tag == DW_TAG_volatile_type ||
+		 tag == DW_TAG_shared_type ||
+		 tag == DW_TAG_typedef);
+
+	return die_mem;
+}
+
 /* Return values for die_find callbacks */
 enum {
 	DIE_FIND_CB_FOUND = 0,		/* End of Search */
@@ -314,6 +336,25 @@ static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
 			      die_mem);
 }
 
+static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
+{
+	const char *name = data;
+
+	if ((dwarf_tag(die_mem) == DW_TAG_member) &&
+	    (die_compare_name(die_mem, name) == 0))
+		return DIE_FIND_CB_FOUND;
+
+	return DIE_FIND_CB_SIBLING;
+}
+
+/* Find a member called 'name' */
+static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
+				  Dwarf_Die *die_mem)
+{
+	return die_find_child(st_die, __die_find_member_cb, (void *)name,
+			      die_mem);
+}
+
 /*
  * Probe finder related functions
  */
@@ -363,6 +404,62 @@ static void convert_location(Dwarf_Op *op, struct probe_finder *pf)
 	}
 }
 
+static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
+				    struct perf_probe_arg_field *field,
+				    struct kprobe_trace_arg_ref **ref_ptr)
+{
+	struct kprobe_trace_arg_ref *ref = *ref_ptr;
+	Dwarf_Attribute attr;
+	Dwarf_Die member;
+	Dwarf_Die type;
+	Dwarf_Word offs;
+
+	pr_debug("converting %s in %s\n", field->name, varname);
+	if (die_get_real_type(vr_die, &type) == NULL)
+		die("Failed to get a type information of %s.", varname);
+
+	/* Check the pointer and dereference */
+	if (dwarf_tag(&type) == DW_TAG_pointer_type) {
+		if (!field->ref)
+			die("Semantic error: %s must be referred by '->'",
+			    field->name);
+		/* Get the type pointed by this pointer */
+		if (die_get_real_type(&type, &type) == NULL)
+			die("Failed to get a type information of %s.", varname);
+
+		ref = xzalloc(sizeof(struct kprobe_trace_arg_ref));
+		if (*ref_ptr)
+			(*ref_ptr)->next = ref;
+		else
+			*ref_ptr = ref;
+	} else {
+		if (field->ref)
+			die("Semantic error: %s must be referred by '.'",
+			    field->name);
+		if (!ref)
+			die("Structure on a register is not supported yet.");
+	}
+
+	/* Verify it is a data structure  */
+	if (dwarf_tag(&type) != DW_TAG_structure_type)
+		die("%s is not a data structure.", varname);
+
+	if (die_find_member(&type, field->name, &member) == NULL)
+		die("%s(tyep:%s) has no member %s.", varname,
+		    dwarf_diename(&type), field->name);
+
+	/* Get the offset of the field */
+	if (dwarf_attr(&member, DW_AT_data_member_location, &attr) == NULL ||
+	    dwarf_formudata(&attr, &offs) != 0)
+		die("Failed to get the offset of %s.", field->name);
+	ref->offset += (long)offs;
+
+	/* Converting next field */
+	if (field->next)
+		convert_variable_fields(&member, field->name, field->next,
+					&ref);
+}
+
 /* Show a variables in kprobe event format */
 static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 {
@@ -379,6 +476,10 @@ static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 		goto error;
 
 	convert_location(expr, pf);
+
+	if (pf->pvar->field)
+		convert_variable_fields(vr_die, pf->pvar->name,
+					pf->pvar->field, &pf->tvar->ref);
 	/* *expr will be cached in libdw. Don't free it. */
 	return ;
 error:
@@ -391,13 +492,15 @@ error:
 static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
 	Dwarf_Die vr_die;
+	char buf[128];
 
 	/* TODO: Support struct members and arrays */
 	if (!is_c_varname(pf->pvar->name)) {
 		/* Copy raw parameters */
 		pf->tvar->value = xstrdup(pf->pvar->name);
 	} else {
-		pf->tvar->name = xstrdup(pf->pvar->name);
+		synthesize_perf_probe_arg(pf->pvar, buf, 128);
+		pf->tvar->name = xstrdup(buf);
 		pr_debug("Searching '%s' variable in context.\n",
 			 pf->pvar->name);
 		/* Search child die for local variables and parameters. */

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

* [tip:perf/core] perf probe: Fix !dwarf build
  2010-03-16 22:06 ` [PATCH -tip 08/10] perf probe: Introduce kprobe_trace_event and perf_probe_event Masami Hiramatsu
  2010-03-17 11:29   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
@ 2010-03-17 11:30   ` tip-bot for Ingo Molnar
  2010-03-17 14:14     ` Masami Hiramatsu
  2010-03-18 17:38   ` [tip:perf/core] perf events: Fix false positive build warning with older GCC's tip-bot for Ingo Molnar
  2 siblings, 1 reply; 32+ messages in thread
From: tip-bot for Ingo Molnar @ 2010-03-17 11:30 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, paulus, acme, hpa, mingo, a.p.zijlstra, efault,
	fweisbec, tglx, mhiramat, mingo

Commit-ID:  3b0d516463f8deb897a55cb81e9dbbe58a2490ed
Gitweb:     http://git.kernel.org/tip/3b0d516463f8deb897a55cb81e9dbbe58a2490ed
Author:     Ingo Molnar <mingo@elte.hu>
AuthorDate: Wed, 17 Mar 2010 12:13:28 +0100
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Wed, 17 Mar 2010 12:13:28 +0100

perf probe: Fix !dwarf build

Fix the !drawf build.

This uses the existing NO_DWARF_SUPPORT mechanism we use for that,
but it's really fragile and needs a cleanup. (in a separate patch)

1) Such uses:

 #ifndef NO_DWARF_SUPPORT

are double inverted logic a'la 'not not'. Instead the flag should
be called DWARF_SUPPORT.

2) Furthermore, assymetric #ifdef polluted code flow like:

        if (need_dwarf)
 #ifdef NO_DWARF_SUPPORT
                die("Debuginfo-analysis is not supported");
 #else   /* !NO_DWARF_SUPPORT */
                pr_debug("Some probes require debuginfo.\n");

        fd = open_vmlinux();

is very fragile and not acceptable. Instead of that helper functions
should be created and the dwarf/no-dwarf logic should be separated more
cleanly.

3) Local variable #ifdefs like this:

 #ifndef NO_DWARF_SUPPORT
        int fd;
 #endif

Are fragile as well and should be eliminated. Helper functions achieve
that too.

Cc: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220612.32050.33806.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 tools/perf/util/probe-event.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 64dea6c..f333269 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1012,8 +1012,10 @@ end_dwarf:
 	if (!sym)
 		die("Kernel symbol \'%s\' not found - probe not added.",
 		    tev->point.symbol);
+#ifndef NO_DWARF_SUPPORT
 found:
 	close(fd);
+#endif
 	return ntevs;
 }
 
@@ -1172,10 +1174,13 @@ void show_line_range(struct line_range *lr)
 	unsigned int l = 1;
 	struct line_node *ln;
 	FILE *fp;
+#ifndef NO_DWARF_SUPPORT
 	int fd, ret;
+#endif
 
 	/* Search a line range */
 	init_vmlinux();
+#ifndef NO_DWARF_SUPPORT
 	fd = open_vmlinux();
 	if (fd < 0)
 		die("Could not open debuginfo file.");
@@ -1183,6 +1188,7 @@ void show_line_range(struct line_range *lr)
 	if (ret <= 0)
 		die("Source line is not found.\n");
 	close(fd);
+#endif
 
 	setup_pager();
 

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

* Re: [tip:perf/core] perf probe: Fix !dwarf build
  2010-03-17 11:30   ` [tip:perf/core] perf probe: Fix !dwarf build tip-bot for Ingo Molnar
@ 2010-03-17 14:14     ` Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-17 14:14 UTC (permalink / raw)
  To: mingo, hpa, acme, paulus, linux-kernel, fweisbec, a.p.zijlstra,
	efault, tglx, mhiramat, mingo
  Cc: linux-tip-commits

Oops, thank you,

Acked-by: Masami Hiramatsu <mhiramat@redhat.com>

tip-bot for Ingo Molnar wrote:
> Commit-ID:  3b0d516463f8deb897a55cb81e9dbbe58a2490ed
> Gitweb:     http://git.kernel.org/tip/3b0d516463f8deb897a55cb81e9dbbe58a2490ed
> Author:     Ingo Molnar <mingo@elte.hu>
> AuthorDate: Wed, 17 Mar 2010 12:13:28 +0100
> Committer:  Ingo Molnar <mingo@elte.hu>
> CommitDate: Wed, 17 Mar 2010 12:13:28 +0100
> 
> perf probe: Fix !dwarf build
> 
> Fix the !drawf build.
> 
> This uses the existing NO_DWARF_SUPPORT mechanism we use for that,
> but it's really fragile and needs a cleanup. (in a separate patch)
> 
> 1) Such uses:
> 
>  #ifndef NO_DWARF_SUPPORT
> 
> are double inverted logic a'la 'not not'. Instead the flag should
> be called DWARF_SUPPORT.
> 
> 2) Furthermore, assymetric #ifdef polluted code flow like:
> 
>         if (need_dwarf)
>  #ifdef NO_DWARF_SUPPORT
>                 die("Debuginfo-analysis is not supported");
>  #else   /* !NO_DWARF_SUPPORT */
>                 pr_debug("Some probes require debuginfo.\n");
> 
>         fd = open_vmlinux();
> 
> is very fragile and not acceptable. Instead of that helper functions
> should be created and the dwarf/no-dwarf logic should be separated more
> cleanly.
> 
> 3) Local variable #ifdefs like this:
> 
>  #ifndef NO_DWARF_SUPPORT
>         int fd;
>  #endif
> 
> Are fragile as well and should be eliminated. Helper functions achieve
> that too.
> 
> Cc: Masami Hiramatsu <mhiramat@redhat.com>
> Cc: Frederic Weisbecker <fweisbec@gmail.com>
> Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: Mike Galbraith <efault@gmx.de>
> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
> LKML-Reference: <20100316220612.32050.33806.stgit@localhost6.localdomain6>
> Signed-off-by: Ingo Molnar <mingo@elte.hu>
> ---
>  tools/perf/util/probe-event.c |    6 ++++++
>  1 files changed, 6 insertions(+), 0 deletions(-)
> 
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index 64dea6c..f333269 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -1012,8 +1012,10 @@ end_dwarf:
>  	if (!sym)
>  		die("Kernel symbol \'%s\' not found - probe not added.",
>  		    tev->point.symbol);
> +#ifndef NO_DWARF_SUPPORT
>  found:
>  	close(fd);
> +#endif
>  	return ntevs;
>  }
>  
> @@ -1172,10 +1174,13 @@ void show_line_range(struct line_range *lr)
>  	unsigned int l = 1;
>  	struct line_node *ln;
>  	FILE *fp;
> +#ifndef NO_DWARF_SUPPORT
>  	int fd, ret;
> +#endif
>  
>  	/* Search a line range */
>  	init_vmlinux();
> +#ifndef NO_DWARF_SUPPORT
>  	fd = open_vmlinux();
>  	if (fd < 0)
>  		die("Could not open debuginfo file.");
> @@ -1183,6 +1188,7 @@ void show_line_range(struct line_range *lr)
>  	if (ret <= 0)
>  		die("Source line is not found.\n");
>  	close(fd);
> +#endif
>  
>  	setup_pager();
>  

-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com


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

* Re: [PATCH -tip 10/10] perf probe: Accessing members in data structures
  2010-03-17 10:25   ` Mark Wielaard
@ 2010-03-17 19:14     ` Masami Hiramatsu
  2010-03-18  3:28       ` Frederic Weisbecker
  0 siblings, 1 reply; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-17 19:14 UTC (permalink / raw)
  To: Mark Wielaard
  Cc: Ingo Molnar, lkml, systemtap, DLE, Frederic Weisbecker,
	Arnaldo Carvalho de Melo, Paul Mackerras, Mike Galbraith,
	Peter Zijlstra

Mark Wielaard wrote:
> On Tue, 2010-03-16 at 18:06 -0400, Masami Hiramatsu wrote:
>> Support accessing members in the data structures. With this,
>> perf-probe accepts data-structure members(IOW, it now accepts
>> dot '.' and arrow '->' operators) as probe arguemnts.
>>
>> e.g.
>>
>>  ./perf probe --add 'schedule:44 rq->curr'
>>
>>  ./perf probe --add 'vfs_read file->f_op->read file->f_path.dentry'
>>
>> Note that '>' can be interpreted as redirection in command-line.
> 
> If you find that a problem then you can do like SystemTap does and allow
> '.' in place of '->'. In the code you already use the
> perf_probe_arg_field ref flag only to check that the DIE gives you the
> same information. So you could just drop that and use any separator.
> Then you decide based on whether you see a DW_TAG_pointer_type. This
> gives the user some extra flexibility by letting them not having to care
> about specifying extra type information already available elsewhere.

Thanks, when designing this feature, I considered it too.

Since perf probe already support displaying source code by --line option,
users will read the probed code itself and try to probe it. In that case,
I think they naturally use '.' and '->' as they read (they might try to
copy & paste it).

So, I think that it would be good to support both of '.' and '->' as
they are used in the code, because it will not confuse users.

Thank you,

-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* Re: [PATCH -tip 10/10] perf probe: Accessing members in data structures
  2010-03-17 19:14     ` Masami Hiramatsu
@ 2010-03-18  3:28       ` Frederic Weisbecker
  2010-03-20  4:20         ` Masami Hiramatsu
  2010-03-23 15:55         ` Peter Zijlstra
  0 siblings, 2 replies; 32+ messages in thread
From: Frederic Weisbecker @ 2010-03-18  3:28 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Mark Wielaard, Ingo Molnar, lkml, systemtap, DLE,
	Arnaldo Carvalho de Melo, Paul Mackerras, Mike Galbraith,
	Peter Zijlstra

On Wed, Mar 17, 2010 at 03:14:43PM -0400, Masami Hiramatsu wrote:
> Mark Wielaard wrote:
> > On Tue, 2010-03-16 at 18:06 -0400, Masami Hiramatsu wrote:
> >> Support accessing members in the data structures. With this,
> >> perf-probe accepts data-structure members(IOW, it now accepts
> >> dot '.' and arrow '->' operators) as probe arguemnts.
> >>
> >> e.g.
> >>
> >>  ./perf probe --add 'schedule:44 rq->curr'
> >>
> >>  ./perf probe --add 'vfs_read file->f_op->read file->f_path.dentry'
> >>
> >> Note that '>' can be interpreted as redirection in command-line.
> > 
> > If you find that a problem then you can do like SystemTap does and allow
> > '.' in place of '->'. In the code you already use the
> > perf_probe_arg_field ref flag only to check that the DIE gives you the
> > same information. So you could just drop that and use any separator.
> > Then you decide based on whether you see a DW_TAG_pointer_type. This
> > gives the user some extra flexibility by letting them not having to care
> > about specifying extra type information already available elsewhere.
> 
> Thanks, when designing this feature, I considered it too.
> 
> Since perf probe already support displaying source code by --line option,
> users will read the probed code itself and try to probe it. In that case,
> I think they naturally use '.' and '->' as they read (they might try to
> copy & paste it).
> 
> So, I think that it would be good to support both of '.' and '->' as
> they are used in the code, because it will not confuse users.
> 
> Thank you,


Agreed.

And lets people use what is common for them: expressions that follow
C rules in the context.

And those who will be more familiar with perf probe will know they can
use the simplified "." based scheme.


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

* [tip:perf/core] perf events: Fix false positive build warning with older GCC's
  2010-03-16 22:06 ` [PATCH -tip 08/10] perf probe: Introduce kprobe_trace_event and perf_probe_event Masami Hiramatsu
  2010-03-17 11:29   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2010-03-17 11:30   ` [tip:perf/core] perf probe: Fix !dwarf build tip-bot for Ingo Molnar
@ 2010-03-18 17:38   ` tip-bot for Ingo Molnar
  2010-03-18 20:03     ` Masami Hiramatsu
  2 siblings, 1 reply; 32+ messages in thread
From: tip-bot for Ingo Molnar @ 2010-03-18 17:38 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, paulus, acme, hpa, mingo, a.p.zijlstra, efault,
	fweisbec, tglx, mhiramat, mingo

Commit-ID:  55632770d7298835645489828af87f854c47749c
Gitweb:     http://git.kernel.org/tip/55632770d7298835645489828af87f854c47749c
Author:     Ingo Molnar <mingo@elte.hu>
AuthorDate: Thu, 18 Mar 2010 16:51:16 +0100
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Thu, 18 Mar 2010 17:03:24 +0100

perf events: Fix false positive build warning with older GCC's

gcc 4.2.1 produces:

 util/probe-event.c: In function 'add_perf_probe_events':
 util/probe-event.c:883: warning: 'tev' may be used uninitialized in this function
 make: *** [util/probe-event.o] Error 1

Newer GCCs get this right.

To work it around, initialize the variable to NULL so that older GCCs see
it as initialized too.

Cc: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220612.32050.33806.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
 tools/perf/util/probe-event.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f333269..c6603f3 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -880,7 +880,7 @@ static void __add_kprobe_trace_events(struct perf_probe_event *pev,
 				      int ntevs, bool allow_suffix)
 {
 	int i, fd;
-	struct kprobe_trace_event *tev;
+	struct kprobe_trace_event *tev = NULL;
 	char buf[64];
 	const char *event, *group;
 	struct strlist *namelist;

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

* Re: [tip:perf/core] perf events: Fix false positive build warning with older GCC's
  2010-03-18 17:38   ` [tip:perf/core] perf events: Fix false positive build warning with older GCC's tip-bot for Ingo Molnar
@ 2010-03-18 20:03     ` Masami Hiramatsu
  0 siblings, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-18 20:03 UTC (permalink / raw)
  To: mingo, hpa, acme, paulus, linux-kernel, fweisbec, a.p.zijlstra,
	efault, tglx, mhiramat, mingo
  Cc: linux-tip-commits

tip-bot for Ingo Molnar wrote:
> Commit-ID:  55632770d7298835645489828af87f854c47749c
> Gitweb:     http://git.kernel.org/tip/55632770d7298835645489828af87f854c47749c
> Author:     Ingo Molnar <mingo@elte.hu>
> AuthorDate: Thu, 18 Mar 2010 16:51:16 +0100
> Committer:  Ingo Molnar <mingo@elte.hu>
> CommitDate: Thu, 18 Mar 2010 17:03:24 +0100
> 
> perf events: Fix false positive build warning with older GCC's
> 
> gcc 4.2.1 produces:
> 
>  util/probe-event.c: In function 'add_perf_probe_events':
>  util/probe-event.c:883: warning: 'tev' may be used uninitialized in this function
>  make: *** [util/probe-event.o] Error 1
> 
> Newer GCCs get this right.
> 
> To work it around, initialize the variable to NULL so that older GCCs see
> it as initialized too.

Hmm, indeed. this code implies that ntevs > 0, it seems that we'd better
check it first (e.g. 'if(ntevs <= 0) return;') too.

Thank you,

> 
> Cc: Masami Hiramatsu <mhiramat@redhat.com>
> Cc: Frederic Weisbecker <fweisbec@gmail.com>
> Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: Mike Galbraith <efault@gmx.de>
> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
> LKML-Reference: <20100316220612.32050.33806.stgit@localhost6.localdomain6>
> Signed-off-by: Ingo Molnar <mingo@elte.hu>
> ---
>  tools/perf/util/probe-event.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index f333269..c6603f3 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -880,7 +880,7 @@ static void __add_kprobe_trace_events(struct perf_probe_event *pev,
>  				      int ntevs, bool allow_suffix)
>  {
>  	int i, fd;
> -	struct kprobe_trace_event *tev;
> +	struct kprobe_trace_event *tev = NULL;
>  	char buf[64];
>  	const char *event, *group;
>  	struct strlist *namelist;
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* Re: [PATCH -tip 10/10] perf probe: Accessing members in data structures
  2010-03-18  3:28       ` Frederic Weisbecker
@ 2010-03-20  4:20         ` Masami Hiramatsu
  2010-03-23 15:55         ` Peter Zijlstra
  1 sibling, 0 replies; 32+ messages in thread
From: Masami Hiramatsu @ 2010-03-20  4:20 UTC (permalink / raw)
  To: Frederic Weisbecker, Steven Rostedt
  Cc: Mark Wielaard, Ingo Molnar, lkml, systemtap, DLE,
	Arnaldo Carvalho de Melo, Paul Mackerras, Mike Galbraith,
	Peter Zijlstra

Frederic Weisbecker wrote:
> On Wed, Mar 17, 2010 at 03:14:43PM -0400, Masami Hiramatsu wrote:
>> Mark Wielaard wrote:
>>> On Tue, 2010-03-16 at 18:06 -0400, Masami Hiramatsu wrote:
>>>> Support accessing members in the data structures. With this,
>>>> perf-probe accepts data-structure members(IOW, it now accepts
>>>> dot '.' and arrow '->' operators) as probe arguemnts.
>>>>
>>>> e.g.
>>>>
>>>>  ./perf probe --add 'schedule:44 rq->curr'
>>>>
>>>>  ./perf probe --add 'vfs_read file->f_op->read file->f_path.dentry'
>>>>
>>>> Note that '>' can be interpreted as redirection in command-line.
>>>
>>> If you find that a problem then you can do like SystemTap does and allow
>>> '.' in place of '->'. In the code you already use the
>>> perf_probe_arg_field ref flag only to check that the DIE gives you the
>>> same information. So you could just drop that and use any separator.
>>> Then you decide based on whether you see a DW_TAG_pointer_type. This
>>> gives the user some extra flexibility by letting them not having to care
>>> about specifying extra type information already available elsewhere.
>>
>> Thanks, when designing this feature, I considered it too.
>>
>> Since perf probe already support displaying source code by --line option,
>> users will read the probed code itself and try to probe it. In that case,
>> I think they naturally use '.' and '->' as they read (they might try to
>> copy & paste it).
>>
>> So, I think that it would be good to support both of '.' and '->' as
>> they are used in the code, because it will not confuse users.
>>
>> Thank you,
> 
> 
> Agreed.
> 
> And lets people use what is common for them: expressions that follow
> C rules in the context.
> 
> And those who will be more familiar with perf probe will know they can
> use the simplified "." based scheme.

Hi Frederic, Steven,

BTW, currently perf trace can't parse these 'data structure' type
field yet.

e.g.
execute following commands;

./perf probe vfs_read 'file->f_mode'
./perf record -e probe:vfs_read -afR ls  -l
./perf trace
  Warning: Error: expected ';' but read '->'
  Warning: failed to read event format for vfs_read

Because perf trace expects that the field name should be a
C-variable name. Moreover, if perf probe supports array element,
it becomes more problematic, e.g. 'field:u8 array[8]'! oops!
what does the field contain? an array with 8 elements? or
8th element of 'array' array? :(

Should I suppose that trace event format only accept C-style
variable name for field?


Thank you,

-- 
Masami Hiramatsu
e-mail: mhiramat@redhat.com

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

* Re: [PATCH -tip 10/10] perf probe: Accessing members in data structures
  2010-03-18  3:28       ` Frederic Weisbecker
  2010-03-20  4:20         ` Masami Hiramatsu
@ 2010-03-23 15:55         ` Peter Zijlstra
  2010-03-23 16:27           ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 32+ messages in thread
From: Peter Zijlstra @ 2010-03-23 15:55 UTC (permalink / raw)
  To: Frederic Weisbecker
  Cc: Masami Hiramatsu, Mark Wielaard, Ingo Molnar, lkml, systemtap,
	DLE, Arnaldo Carvalho de Melo, Paul Mackerras, Mike Galbraith

On Thu, 2010-03-18 at 04:28 +0100, Frederic Weisbecker wrote:
> On Wed, Mar 17, 2010 at 03:14:43PM -0400, Masami Hiramatsu wrote:
> > Mark Wielaard wrote:
> > > On Tue, 2010-03-16 at 18:06 -0400, Masami Hiramatsu wrote:
> > >> Support accessing members in the data structures. With this,
> > >> perf-probe accepts data-structure members(IOW, it now accepts
> > >> dot '.' and arrow '->' operators) as probe arguemnts.
> > >>
> > >> e.g.
> > >>
> > >>  ./perf probe --add 'schedule:44 rq->curr'
> > >>
> > >>  ./perf probe --add 'vfs_read file->f_op->read file->f_path.dentry'
> > >>
> > >> Note that '>' can be interpreted as redirection in command-line.
> > > 
> > > If you find that a problem then you can do like SystemTap does and allow
> > > '.' in place of '->'. In the code you already use the
> > > perf_probe_arg_field ref flag only to check that the DIE gives you the
> > > same information. So you could just drop that and use any separator.
> > > Then you decide based on whether you see a DW_TAG_pointer_type. This
> > > gives the user some extra flexibility by letting them not having to care
> > > about specifying extra type information already available elsewhere.
> > 
> > Thanks, when designing this feature, I considered it too.
> > 
> > Since perf probe already support displaying source code by --line option,
> > users will read the probed code itself and try to probe it. In that case,
> > I think they naturally use '.' and '->' as they read (they might try to
> > copy & paste it).
> > 
> > So, I think that it would be good to support both of '.' and '->' as
> > they are used in the code, because it will not confuse users.
> > 
> > Thank you,
> 
> 
> Agreed.
> 
> And lets people use what is common for them: expressions that follow
> C rules in the context.
> 
> And those who will be more familiar with perf probe will know they can
> use the simplified "." based scheme.

I'd expect a syntax error when I mix up '.' and '->'.

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

* Re: [PATCH -tip 10/10] perf probe: Accessing members in data structures
  2010-03-23 15:55         ` Peter Zijlstra
@ 2010-03-23 16:27           ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 32+ messages in thread
From: Arnaldo Carvalho de Melo @ 2010-03-23 16:27 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Frederic Weisbecker, Masami Hiramatsu, Mark Wielaard,
	Ingo Molnar, lkml, systemtap, DLE, Paul Mackerras,
	Mike Galbraith

Em Tue, Mar 23, 2010 at 04:55:13PM +0100, Peter Zijlstra escreveu:
> On Thu, 2010-03-18 at 04:28 +0100, Frederic Weisbecker wrote:
> > On Wed, Mar 17, 2010 at 03:14:43PM -0400, Masami Hiramatsu wrote:
> > > Mark Wielaard wrote:
> > > > If you find that a problem then you can do like SystemTap does and allow
> > > > '.' in place of '->'. In the code you already use the
> > > > perf_probe_arg_field ref flag only to check that the DIE gives you the
> > > > same information. So you could just drop that and use any separator.
> > > > Then you decide based on whether you see a DW_TAG_pointer_type. This
> > > > gives the user some extra flexibility by letting them not having to care
> > > > about specifying extra type information already available elsewhere.

> > > Thanks, when designing this feature, I considered it too.

> > > Since perf probe already support displaying source code by --line option,
> > > users will read the probed code itself and try to probe it. In that case,
> > > I think they naturally use '.' and '->' as they read (they might try to
> > > copy & paste it).

> > > So, I think that it would be good to support both of '.' and '->' as
> > > they are used in the code, because it will not confuse users.

> > And lets people use what is common for them: expressions that follow
> > C rules in the context.

> > And those who will be more familiar with perf probe will know they can
> > use the simplified "." based scheme.

> I'd expect a syntax error when I mix up '.' and '->'.

Yup, I'd stick with following the C language rules.

- Arnaldo

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

end of thread, other threads:[~2010-03-23 16:27 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-16 22:05 [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Masami Hiramatsu
2010-03-16 22:05 ` [PATCH -tip 01/10] perf tools: Introduce xzalloc() for detecting out of memory Masami Hiramatsu
2010-03-17 11:27   ` [tip:perf/core] perf tools: Introduce xzalloc() for detecting out of memory conditions tip-bot for Masami Hiramatsu
2010-03-16 22:05 ` [PATCH -tip 02/10] perf probe: Use wrapper functions Masami Hiramatsu
2010-03-17 11:27   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-16 22:05 ` [PATCH -tip 03/10] perf probe: Move add-probe routine under util/ Masami Hiramatsu
2010-03-17 11:28   ` [tip:perf/core] perf probe: Move add-probe routine to util/ tip-bot for Masami Hiramatsu
2010-03-16 22:05 ` [PATCH -tip 04/10] perf probe: Rename session to param Masami Hiramatsu
2010-03-17 11:28   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-16 22:05 ` [PATCH -tip 05/10] perf probe: Rename some die_get_* functions Masami Hiramatsu
2010-03-17 11:28   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-16 22:05 ` [PATCH -tip 06/10] perf probe: Introduce die_find_child() function Masami Hiramatsu
2010-03-17 11:29   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-16 22:06 ` [PATCH -tip 07/10] perf probe: Add --dry-run option Masami Hiramatsu
2010-03-17 11:29   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-16 22:06 ` [PATCH -tip 08/10] perf probe: Introduce kprobe_trace_event and perf_probe_event Masami Hiramatsu
2010-03-17 11:29   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-17 11:30   ` [tip:perf/core] perf probe: Fix !dwarf build tip-bot for Ingo Molnar
2010-03-17 14:14     ` Masami Hiramatsu
2010-03-18 17:38   ` [tip:perf/core] perf events: Fix false positive build warning with older GCC's tip-bot for Ingo Molnar
2010-03-18 20:03     ` Masami Hiramatsu
2010-03-16 22:06 ` [PATCH -tip 09/10] perf probe: List probes with line number and file name Masami Hiramatsu
2010-03-17 11:29   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2010-03-16 22:06 ` [PATCH -tip 10/10] perf probe: Accessing members in data structures Masami Hiramatsu
2010-03-17 10:25   ` Mark Wielaard
2010-03-17 19:14     ` Masami Hiramatsu
2010-03-18  3:28       ` Frederic Weisbecker
2010-03-20  4:20         ` Masami Hiramatsu
2010-03-23 15:55         ` Peter Zijlstra
2010-03-23 16:27           ` Arnaldo Carvalho de Melo
2010-03-17 11:30   ` [tip:perf/core] perf probe: Add data structure member access support tip-bot for Masami Hiramatsu
2010-03-17 10:34 ` [PATCH -tip 00/10] perf-probe updates - data-structure support, etc Ingo Molnar

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.