public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH -tip  0/7] Perf probe update (--vars/--module)
@ 2010-10-21 10:12 Masami Hiramatsu
  2010-10-21 10:13 ` [PATCH -tip 1/7] [BUGFIX] perf probe: Fix type searching Masami Hiramatsu
                   ` (6 more replies)
  0 siblings, 7 replies; 18+ messages in thread
From: Masami Hiramatsu @ 2010-10-21 10:12 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Peter Zijlstra, Paul Mackerras, Frederic Weisbecker,
	Steven Rostedt, Srikar Dronamraju, linux-kernel, 2nddept-manager

Hi,

This series fixes several variable-access problems, a style issue 
and adds two features; showing available variables and
module probing support. :)

Thank you,

---

Masami Hiramatsu (7):
      perf probe: Add basic module support
      perf probe: Show accessible global variables
      perf probe: Function style fix
      perf probe: Show accessible local variables
      perf probe: Support global variables
      [BUGFIX] perf probe: Fix local variable searching loop
      [BUGFIX] perf probe: Fix type searching


 tools/perf/Documentation/perf-probe.txt |   18 +
 tools/perf/builtin-probe.c              |   78 +++-
 tools/perf/util/map.h                   |   10 
 tools/perf/util/probe-event.c           |  189 +++++++--
 tools/perf/util/probe-event.h           |   16 +
 tools/perf/util/probe-finder.c          |  644 +++++++++++++++++++++++++------
 tools/perf/util/probe-finder.h          |   31 +
 7 files changed, 793 insertions(+), 193 deletions(-)

-- 
Masami HIRAMATSU
2nd Dept. Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com


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

* [PATCH -tip  1/7] [BUGFIX] perf probe: Fix type searching
  2010-10-21 10:12 [PATCH -tip 0/7] Perf probe update (--vars/--module) Masami Hiramatsu
@ 2010-10-21 10:13 ` Masami Hiramatsu
  2010-10-23 19:40   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
  2010-10-21 10:13 ` [PATCH -tip 2/7] [BUGFIX] perf probe: Fix local variable searching loop Masami Hiramatsu
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 18+ messages in thread
From: Masami Hiramatsu @ 2010-10-21 10:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, linux-kernel, 2nddept-manager,
	Masami Hiramatsu, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo, linux-kernel

Fix to get the actual type die of variables by
using dwarf_attr_integrate() which gets attribute
from die even if the type die is connected by
DW_AT_abstract_origin.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: linux-kernel@vger.kernel.org
---

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

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 32b81f7..a2d1f79 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -160,26 +160,35 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
 	return name ? (strcmp(tname, name) == 0) : false;
 }
 
+/* Get type die */
+static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+{
+	Dwarf_Attribute attr;
+
+	if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
+	    dwarf_formref_die(&attr, die_mem))
+		return die_mem;
+	else
+		return NULL;
+}
+
 /* 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;
+		vr_die = die_get_type(vr_die, die_mem);
+		if (!vr_die)
+			break;
+		tag = dwarf_tag(vr_die);
 	} 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 vr_die;
 }
 
 static bool die_is_signed_type(Dwarf_Die *tp_die)


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

* [PATCH -tip 2/7] [BUGFIX] perf probe: Fix local variable searching loop
  2010-10-21 10:12 [PATCH -tip 0/7] Perf probe update (--vars/--module) Masami Hiramatsu
  2010-10-21 10:13 ` [PATCH -tip 1/7] [BUGFIX] perf probe: Fix type searching Masami Hiramatsu
@ 2010-10-21 10:13 ` Masami Hiramatsu
  2010-10-23 19:40   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
  2010-10-21 10:13 ` [PATCH -tip 3/7] perf probe: Support global variables Masami Hiramatsu
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 18+ messages in thread
From: Masami Hiramatsu @ 2010-10-21 10:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, linux-kernel, 2nddept-manager,
	Masami Hiramatsu, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo, linux-kernel

Fix to check the die's address and search into the die
only if it has given address.
This will avoid finding wrong variables in wrong
basic block.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: linux-kernel@vger.kernel.org
---

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

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index a2d1f79..abcaec5 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -329,25 +329,35 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
 	return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
 }
 
+struct __find_variable_param {
+	const char *name;
+	Dwarf_Addr addr;
+};
+
 static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
 {
-	const char *name = data;
+	struct __find_variable_param *fvp = data;
 	int tag;
 
 	tag = dwarf_tag(die_mem);
 	if ((tag == DW_TAG_formal_parameter ||
 	     tag == DW_TAG_variable) &&
-	    die_compare_name(die_mem, name))
+	    die_compare_name(die_mem, fvp->name))
 		return DIE_FIND_CB_FOUND;
 
-	return DIE_FIND_CB_CONTINUE;
+	if (dwarf_haspc(die_mem, fvp->addr))
+		return DIE_FIND_CB_CONTINUE;
+	else
+		return DIE_FIND_CB_SIBLING;
 }
 
-/* Find a variable called 'name' */
-static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
-				    Dwarf_Die *die_mem)
+/* Find a variable called 'name' at given address */
+static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
+				       Dwarf_Addr addr, Dwarf_Die *die_mem)
 {
-	return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
+	struct __find_variable_param fvp = { .name = name, .addr = addr};
+
+	return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
 			      die_mem);
 }
 
@@ -731,7 +741,7 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
 	pr_debug("Searching '%s' variable in context.\n",
 		 pf->pvar->var);
 	/* Search child die for local variables and parameters. */
-	if (die_find_variable(sp_die, pf->pvar->var, &vr_die))
+	if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die))
 		ret = convert_variable(&vr_die, pf);
 	else {
 		/* Search upper class */


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

* [PATCH -tip  3/7] perf probe: Support global variables
  2010-10-21 10:12 [PATCH -tip 0/7] Perf probe update (--vars/--module) Masami Hiramatsu
  2010-10-21 10:13 ` [PATCH -tip 1/7] [BUGFIX] perf probe: Fix type searching Masami Hiramatsu
  2010-10-21 10:13 ` [PATCH -tip 2/7] [BUGFIX] perf probe: Fix local variable searching loop Masami Hiramatsu
@ 2010-10-21 10:13 ` Masami Hiramatsu
  2010-10-23 19:40   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
  2010-10-21 10:13 ` [PATCH -tip 4/7] perf probe: Show accessible local variables Masami Hiramatsu
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 18+ messages in thread
From: Masami Hiramatsu @ 2010-10-21 10:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, linux-kernel, 2nddept-manager,
	Masami Hiramatsu, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo, linux-kernel

Allow users to set external defined global variables
as event arguments (e.g. jiffies).

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: linux-kernel@vger.kernel.org
---

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

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index abcaec5..c6fe80e 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -406,6 +406,9 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
 	struct probe_trace_arg *tvar = pf->tvar;
 	int ret;
 
+	if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
+		goto static_var;
+
 	/* TODO: handle more than 1 exprs */
 	if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
 	    dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
@@ -417,6 +420,7 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
 	}
 
 	if (op->atom == DW_OP_addr) {
+static_var:
 		/* Static variables on memory (not stack), make @varname */
 		ret = strlen(dwarf_diename(vr_die));
 		tvar->value = zalloc(ret + 2);
@@ -746,17 +750,22 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
 	else {
 		/* Search upper class */
 		nscopes = dwarf_getscopes_die(sp_die, &scopes);
-		if (nscopes > 0) {
-			ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var,
-						0, NULL, 0, 0, &vr_die);
-			if (ret >= 0)
+		while (nscopes-- > 1) {
+			pr_debug("Searching variables in %s\n",
+				 dwarf_diename(&scopes[nscopes]));
+			/* We should check this scope, so give dummy address */
+			if (die_find_variable_at(&scopes[nscopes],
+						 pf->pvar->var, 0,
+						 &vr_die)) {
 				ret = convert_variable(&vr_die, pf);
-			else
-				ret = -ENOENT;
+				goto found;
+			}
+		}
+		if (scopes)
 			free(scopes);
-		} else
-			ret = -ENOENT;
+		ret = -ENOENT;
 	}
+found:
 	if (ret < 0)
 		pr_warning("Failed to find '%s' in this function.\n",
 			   pf->pvar->var);


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

* [PATCH -tip  4/7] perf probe: Show accessible local variables
  2010-10-21 10:12 [PATCH -tip 0/7] Perf probe update (--vars/--module) Masami Hiramatsu
                   ` (2 preceding siblings ...)
  2010-10-21 10:13 ` [PATCH -tip 3/7] perf probe: Support global variables Masami Hiramatsu
@ 2010-10-21 10:13 ` Masami Hiramatsu
  2010-10-23 19:41   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
  2010-10-21 10:13 ` [PATCH -tip 5/7] perf probe: Function style fix Masami Hiramatsu
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 18+ messages in thread
From: Masami Hiramatsu @ 2010-10-21 10:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, linux-kernel, 2nddept-manager,
	Masami Hiramatsu, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo, Frederic Weisbecker, linux-kernel

Add -V (--vars) option for listing accessible local
variables at given probe point. This will help finding
which local variables are available for event arguments.

e.g.)
# perf probe -V call_timer_fn:23
Available variables at call_timer_fn:23
        @<run_timer_softirq+345>
                function_type*  fn
                int     preempt_count
                long unsigned int       data
                struct list_head        work_list
                struct list_head*       head
                struct timer_list*      timer
                struct tvec_base*       base


Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: linux-kernel@vger.kernel.org
---

 tools/perf/Documentation/perf-probe.txt |    7 +
 tools/perf/builtin-probe.c              |   61 ++++-
 tools/perf/util/probe-event.c           |   72 +++++
 tools/perf/util/probe-event.h           |    8 +
 tools/perf/util/probe-finder.c          |  412 ++++++++++++++++++++++++-------
 tools/perf/util/probe-finder.h          |   25 ++
 6 files changed, 480 insertions(+), 105 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 27d52da..72f5d9e 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -17,6 +17,8 @@ or
 'perf probe' --list
 or
 'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
+or
+'perf probe' --vars='PROBEPOINT'
 
 DESCRIPTION
 -----------
@@ -57,6 +59,11 @@ OPTIONS
 	Show source code lines which can be probed. This needs an argument
 	which specifies a range of the source code. (see LINE SYNTAX for detail)
 
+-V::
+--vars=::
+	Show available local variables at given probe point. The argument
+	syntax is same as PROBE SYNTAX, but NO ARGs.
+
 -f::
 --force::
 	Forcibly add events with existing name.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 199d5e1..91bb6cf 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -50,6 +50,8 @@ static struct {
 	bool list_events;
 	bool force_add;
 	bool show_lines;
+	bool show_vars;
+	bool mod_events;
 	int nevents;
 	struct perf_probe_event events[MAX_PROBES];
 	struct strlist *dellist;
@@ -57,7 +59,6 @@ static struct {
 	int max_probe_points;
 } params;
 
-
 /* Parse an event definition. Note that any error must die. */
 static int parse_probe_event(const char *str)
 {
@@ -92,6 +93,7 @@ static int parse_probe_event_argv(int argc, const char **argv)
 	len = 0;
 	for (i = 0; i < argc; i++)
 		len += sprintf(&buf[len], "%s ", argv[i]);
+	params.mod_events = true;
 	ret = parse_probe_event(buf);
 	free(buf);
 	return ret;
@@ -100,9 +102,10 @@ static int parse_probe_event_argv(int argc, const char **argv)
 static int opt_add_probe_event(const struct option *opt __used,
 			      const char *str, int unset __used)
 {
-	if (str)
+	if (str) {
+		params.mod_events = true;
 		return parse_probe_event(str);
-	else
+	} else
 		return 0;
 }
 
@@ -110,6 +113,7 @@ static int opt_del_probe_event(const struct option *opt __used,
 			       const char *str, int unset __used)
 {
 	if (str) {
+		params.mod_events = true;
 		if (!params.dellist)
 			params.dellist = strlist__new(true, NULL);
 		strlist__add(params.dellist, str);
@@ -130,6 +134,25 @@ static int opt_show_lines(const struct option *opt __used,
 
 	return ret;
 }
+
+static int opt_show_vars(const struct option *opt __used,
+			 const char *str, int unset __used)
+{
+	struct perf_probe_event *pev = &params.events[params.nevents];
+	int ret;
+
+	if (!str)
+		return 0;
+
+	ret = parse_probe_event(str);
+	if (!ret && pev->nargs != 0) {
+		pr_err("  Error: '--vars' doesn't accept arguments.\n");
+		return -EINVAL;
+	}
+	params.show_vars = true;
+
+	return ret;
+}
 #endif
 
 static const char * const probe_usage[] = {
@@ -139,6 +162,7 @@ static const char * const probe_usage[] = {
 	"perf probe --list",
 #ifdef DWARF_SUPPORT
 	"perf probe --line 'LINEDESC'",
+	"perf probe --vars 'PROBEPOINT'",
 #endif
 	NULL
 };
@@ -180,6 +204,9 @@ static const struct option options[] = {
 	OPT_CALLBACK('L', "line", NULL,
 		     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
 		     "Show source code lines.", opt_show_lines),
+	OPT_CALLBACK('V', "vars", NULL,
+		     "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
+		     "Show accessible variables on PROBEDEF", opt_show_vars),
 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 		   "file", "vmlinux pathname"),
 	OPT_STRING('s', "source", &symbol_conf.source_prefix,
@@ -217,7 +244,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		usage_with_options(probe_usage, options);
 
 	if (params.list_events) {
-		if (params.nevents != 0 || params.dellist) {
+		if (params.mod_events) {
 			pr_err("  Error: Don't use --list with --add/--del.\n");
 			usage_with_options(probe_usage, options);
 		}
@@ -225,6 +252,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			pr_err("  Error: Don't use --list with --line.\n");
 			usage_with_options(probe_usage, options);
 		}
+		if (params.show_vars) {
+			pr_err(" Error: Don't use --list with --vars.\n");
+			usage_with_options(probe_usage, options);
+		}
 		ret = show_perf_probe_events();
 		if (ret < 0)
 			pr_err("  Error: Failed to show event list. (%d)\n",
@@ -234,9 +265,13 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 
 #ifdef DWARF_SUPPORT
 	if (params.show_lines) {
-		if (params.nevents != 0 || params.dellist) {
-			pr_warning("  Error: Don't use --line with"
-				   " --add/--del.\n");
+		if (params.mod_events) {
+			pr_err("  Error: Don't use --line with"
+			       " --add/--del.\n");
+			usage_with_options(probe_usage, options);
+		}
+		if (params.show_vars) {
+			pr_err(" Error: Don't use --line with --vars.\n");
 			usage_with_options(probe_usage, options);
 		}
 
@@ -245,6 +280,18 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			pr_err("  Error: Failed to show lines. (%d)\n", ret);
 		return ret;
 	}
+	if (params.show_vars) {
+		if (params.mod_events) {
+			pr_err("  Error: Don't use --vars with"
+			       " --add/--del.\n");
+			usage_with_options(probe_usage, options);
+		}
+		ret = show_available_vars(params.events, params.nevents,
+					  params.max_probe_points);
+		if (ret < 0)
+			pr_err("  Error: Failed to show vars. (%d)\n", ret);
+		return ret;
+	}
 #endif
 
 	if (params.dellist) {
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fcc16e4..3de265e 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -378,6 +378,72 @@ end:
 	return ret;
 }
 
+static int show_available_vars_at(int fd, struct perf_probe_event *pev,
+				  int max_vls)
+{
+	char *buf;
+	int ret, i;
+	struct str_node *node;
+	struct variable_list *vls = NULL, *vl;
+
+	buf = synthesize_perf_probe_point(&pev->point);
+	if (!buf)
+		return -EINVAL;
+	pr_debug("Searching variables at %s\n", buf);
+
+	ret = find_available_vars_at(fd, pev, &vls, max_vls);
+	if (ret > 0) {
+		/* Some variables are found */
+		fprintf(stdout, "Available variables at %s\n", buf);
+		for (i = 0; i < ret; i++) {
+			vl = &vls[i];
+			/*
+			 * A probe point might be converted to
+			 * several trace points.
+			 */
+			fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
+				vl->point.offset);
+			free(vl->point.symbol);
+			if (vl->vars) {
+				strlist__for_each(node, vl->vars)
+					fprintf(stdout, "\t\t%s\n", node->s);
+				strlist__delete(vl->vars);
+			} else
+				fprintf(stdout, "(No variables)\n");
+		}
+		free(vls);
+	} else
+		pr_err("Failed to find variables at %s (%d)\n", buf, ret);
+
+	free(buf);
+	return ret;
+}
+
+/* Show available variables on given probe point */
+int show_available_vars(struct perf_probe_event *pevs, int npevs,
+			int max_vls)
+{
+	int i, fd, ret = 0;
+
+	ret = init_vmlinux();
+	if (ret < 0)
+		return ret;
+
+	fd = open_vmlinux();
+	if (fd < 0) {
+		pr_warning("Failed to open debuginfo file.\n");
+		return fd;
+	}
+
+	setup_pager();
+
+	for (i = 0; i < npevs && ret >= 0; i++)
+		ret = show_available_vars_at(fd, &pevs[i], max_vls);
+
+	close(fd);
+	return ret;
+}
+
 #else	/* !DWARF_SUPPORT */
 
 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
@@ -409,6 +475,12 @@ int show_line_range(struct line_range *lr __unused)
 	return -ENOSYS;
 }
 
+int show_available_vars(struct perf_probe_event *pevs __unused,
+			int npevs __unused, int max_probe_points __unused)
+{
+	pr_warning("Debuginfo-analysis is not supported.\n");
+	return -ENOSYS;
+}
 #endif
 
 int parse_line_range_desc(const char *arg, struct line_range *lr)
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5af3924..727a7fe 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -90,6 +90,12 @@ struct line_range {
 	struct list_head	line_list;	/* Visible lines */
 };
 
+/* List of variables */
+struct variable_list {
+	struct probe_trace_point	point;	/* Actual probepoint */
+	struct strlist			*vars;	/* Available variables */
+};
+
 /* Command string to events */
 extern int parse_perf_probe_command(const char *cmd,
 				    struct perf_probe_event *pev);
@@ -115,6 +121,8 @@ extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
 extern int del_perf_probe_events(struct strlist *dellist);
 extern int show_perf_probe_events(void);
 extern int show_line_range(struct line_range *lr);
+extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
+			       int max_probe_points);
 
 
 /* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c6fe80e..986027f 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -172,8 +172,8 @@ static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
 		return NULL;
 }
 
-/* Get type die, but skip qualifiers and typedef */
-static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+/* Get a type die, but skip qualifiers */
+static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
 {
 	int tag;
 
@@ -185,8 +185,17 @@ static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_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);
+		 tag == DW_TAG_shared_type);
+
+	return vr_die;
+}
+
+/* Get a type die, but skip qualifiers and typedef */
+static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+{
+	do {
+		vr_die = __die_get_real_type(vr_die, die_mem);
+	} while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
 
 	return vr_die;
 }
@@ -380,6 +389,60 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
 			      die_mem);
 }
 
+/* Get the name of given variable DIE */
+static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
+{
+	Dwarf_Die type;
+	int tag, ret, ret2;
+	const char *tmp = "";
+
+	if (__die_get_real_type(vr_die, &type) == NULL)
+		return -ENOENT;
+
+	tag = dwarf_tag(&type);
+	if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
+		tmp = "*";
+	else if (tag == DW_TAG_subroutine_type) {
+		/* Function pointer */
+		ret = snprintf(buf, len, "(function_type)");
+		return (ret >= len) ? -E2BIG : ret;
+	} else {
+		if (!dwarf_diename(&type))
+			return -ENOENT;
+		if (tag == DW_TAG_union_type)
+			tmp = "union ";
+		else if (tag == DW_TAG_structure_type)
+			tmp = "struct ";
+		/* Write a base name */
+		ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
+		return (ret >= len) ? -E2BIG : ret;
+	}
+	ret = die_get_typename(&type, buf, len);
+	if (ret > 0) {
+		ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
+		ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
+	}
+	return ret;
+}
+
+/* Get the name and type of given variable DIE, stored as "type\tname" */
+static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
+{
+	int ret, ret2;
+
+	ret = die_get_typename(vr_die, buf, len);
+	if (ret < 0) {
+		pr_debug("Failed to get type, make it unknown.\n");
+		ret = snprintf(buf, len, "(unknown_type)");
+	}
+	if (ret > 0) {
+		ret2 = snprintf(buf + ret, len - ret, "\t%s",
+				dwarf_diename(vr_die));
+		ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
+	}
+	return ret;
+}
+
 /*
  * Probe finder related functions
  */
@@ -393,8 +456,13 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
 	return ref;
 }
 
-/* Show a location */
-static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
+/*
+ * Convert a location into trace_arg.
+ * If tvar == NULL, this just checks variable can be converted.
+ */
+static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
+				     Dwarf_Op *fb_ops,
+				     struct probe_trace_arg *tvar)
 {
 	Dwarf_Attribute attr;
 	Dwarf_Op *op;
@@ -403,7 +471,6 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
 	Dwarf_Word offs = 0;
 	bool ref = false;
 	const char *regs;
-	struct probe_trace_arg *tvar = pf->tvar;
 	int ret;
 
 	if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
@@ -411,16 +478,16 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
 
 	/* TODO: handle more than 1 exprs */
 	if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
-	    dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
+	    dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||
 	    nops == 0) {
 		/* TODO: Support const_value */
-		pr_err("Failed to find the location of %s at this address.\n"
-		       " Perhaps, it has been optimized out.\n", pf->pvar->var);
 		return -ENOENT;
 	}
 
 	if (op->atom == DW_OP_addr) {
 static_var:
+		if (!tvar)
+			return 0;
 		/* Static variables on memory (not stack), make @varname */
 		ret = strlen(dwarf_diename(vr_die));
 		tvar->value = zalloc(ret + 2);
@@ -435,14 +502,11 @@ static_var:
 
 	/* If this is based on frame buffer, set the offset */
 	if (op->atom == DW_OP_fbreg) {
-		if (pf->fb_ops == NULL) {
-			pr_warning("The attribute of frame base is not "
-				   "supported.\n");
+		if (fb_ops == NULL)
 			return -ENOTSUP;
-		}
 		ref = true;
 		offs = op->number;
-		op = &pf->fb_ops[0];
+		op = &fb_ops[0];
 	}
 
 	if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
@@ -458,13 +522,18 @@ static_var:
 	} else if (op->atom == DW_OP_regx) {
 		regn = op->number;
 	} else {
-		pr_warning("DW_OP %x is not supported.\n", op->atom);
+		pr_debug("DW_OP %x is not supported.\n", op->atom);
 		return -ENOTSUP;
 	}
 
+	if (!tvar)
+		return 0;
+
 	regs = get_arch_regstr(regn);
 	if (!regs) {
-		pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn);
+		/* This should be a bug in DWARF or this tool */
+		pr_warning("Mapping for DWARF register number %u "
+			   "missing on this architecture.", regn);
 		return -ERANGE;
 	}
 
@@ -689,8 +758,14 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 	pr_debug("Converting variable %s into trace event.\n",
 		 dwarf_diename(vr_die));
 
-	ret = convert_variable_location(vr_die, pf);
-	if (ret == 0 && pf->pvar->field) {
+	ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
+					pf->tvar);
+	if (ret == -ENOENT)
+		pr_err("Failed to find the location of %s at this address.\n"
+		       " Perhaps, it has been optimized out.\n", pf->pvar->var);
+	else if (ret == -ENOTSUP)
+		pr_err("Sorry, we don't support this variable location yet.\n");
+	else if (pf->pvar->field) {
 		ret = convert_variable_fields(vr_die, pf->pvar->var,
 					      pf->pvar->field, &pf->tvar->ref,
 					      &die_mem);
@@ -772,34 +847,12 @@ found:
 	return ret;
 }
 
-/* Show a probe point to output buffer */
-static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
+/* Convert subprogram DIE to trace point */
+static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
+				  bool retprobe, struct probe_trace_point *tp)
 {
-	struct probe_trace_event *tev;
 	Dwarf_Addr eaddr;
-	Dwarf_Die die_mem;
 	const char *name;
-	int ret, i;
-	Dwarf_Attribute fb_attr;
-	size_t nops;
-
-	if (pf->ntevs == pf->max_tevs) {
-		pr_warning("Too many( > %d) probe point found.\n",
-			   pf->max_tevs);
-		return -ERANGE;
-	}
-	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,
-						 pf->addr, &die_mem);
-		if (!sp_die) {
-			pr_warning("Failed to find probe point in any "
-				   "functions.\n");
-			return -ENOENT;
-		}
-	}
 
 	/* Copy the name of probe point */
 	name = dwarf_diename(sp_die);
@@ -809,26 +862,45 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 				   dwarf_diename(sp_die));
 			return -ENOENT;
 		}
-		tev->point.symbol = strdup(name);
-		if (tev->point.symbol == NULL)
+		tp->symbol = strdup(name);
+		if (tp->symbol == NULL)
 			return -ENOMEM;
-		tev->point.offset = (unsigned long)(pf->addr - eaddr);
+		tp->offset = (unsigned long)(paddr - eaddr);
 	} else
 		/* This function has no name. */
-		tev->point.offset = (unsigned long)pf->addr;
+		tp->offset = (unsigned long)paddr;
 
 	/* Return probe must be on the head of a subprogram */
-	if (pf->pev->point.retprobe) {
-		if (tev->point.offset != 0) {
+	if (retprobe) {
+		if (eaddr != paddr) {
 			pr_warning("Return probe must be on the head of"
 				   " a real function\n");
 			return -EINVAL;
 		}
-		tev->point.retprobe = true;
+		tp->retprobe = true;
 	}
 
-	pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
-		 tev->point.offset);
+	return 0;
+}
+
+/* Call probe_finder callback with real subprogram DIE */
+static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+	Dwarf_Die die_mem;
+	Dwarf_Attribute fb_attr;
+	size_t nops;
+	int ret;
+
+	/* 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,
+						  pf->addr, &die_mem);
+		if (!sp_die) {
+			pr_warning("Failed to find probe point in any "
+				   "functions.\n");
+			return -ENOENT;
+		}
+	}
 
 	/* Get the frame base attribute/ops */
 	dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
@@ -848,22 +920,13 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 #endif
 	}
 
-	/* Find each argument */
-	tev->nargs = pf->pev->nargs;
-	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
-	if (tev->args == NULL)
-		return -ENOMEM;
-	for (i = 0; i < pf->pev->nargs; i++) {
-		pf->pvar = &pf->pev->args[i];
-		pf->tvar = &tev->args[i];
-		ret = find_variable(sp_die, pf);
-		if (ret != 0)
-			return ret;
-	}
+	/* Call finder's callback handler */
+	ret = pf->callback(sp_die, pf);
 
 	/* *pf->fb_ops will be cached in libdw. Don't free it. */
 	pf->fb_ops = NULL;
-	return 0;
+
+	return ret;
 }
 
 /* Find probe point from its line number */
@@ -899,7 +962,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
 			 (int)i, lineno, (uintmax_t)addr);
 		pf->addr = addr;
 
-		ret = convert_probe_point(NULL, pf);
+		ret = call_probe_finder(NULL, pf);
 		/* Continuing, because target line might be inlined. */
 	}
 	return ret;
@@ -1012,7 +1075,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 			 (int)i, lineno, (unsigned long long)addr);
 		pf->addr = addr;
 
-		ret = convert_probe_point(sp_die, pf);
+		ret = call_probe_finder(sp_die, pf);
 		/* Continuing, because target line might be inlined. */
 	}
 	/* TODO: deallocate lines, but how? */
@@ -1047,7 +1110,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);
 
-		param->retval = convert_probe_point(in_die, pf);
+		param->retval = call_probe_finder(in_die, pf);
 		if (param->retval < 0)
 			return DWARF_CB_ABORT;
 	}
@@ -1085,7 +1148,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
 			}
 			pf->addr += pp->offset;
 			/* TODO: Check the address in this function */
-			param->retval = convert_probe_point(sp_die, pf);
+			param->retval = call_probe_finder(sp_die, pf);
 		}
 	} else {
 		struct dwarf_callback_param _param = {.data = (void *)pf,
@@ -1107,70 +1170,229 @@ static int find_probe_point_by_func(struct probe_finder *pf)
 	return _param.retval;
 }
 
-/* Find probe_trace_events specified by perf_probe_event from debuginfo */
-int find_probe_trace_events(int fd, struct perf_probe_event *pev,
-			     struct probe_trace_event **tevs, int max_tevs)
+/* Find probe points from debuginfo */
+static int find_probes(int fd, struct probe_finder *pf)
 {
-	struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};
-	struct perf_probe_point *pp = &pev->point;
+	struct perf_probe_point *pp = &pf->pev->point;
 	Dwarf_Off off, noff;
 	size_t cuhl;
 	Dwarf_Die *diep;
 	Dwarf *dbg;
 	int ret = 0;
 
-	pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
-	if (pf.tevs == NULL)
-		return -ENOMEM;
-	*tevs = pf.tevs;
-	pf.ntevs = 0;
-
 	dbg = dwarf_begin(fd, DWARF_C_READ);
 	if (!dbg) {
 		pr_warning("No dwarf info found in the vmlinux - "
 			"please rebuild with CONFIG_DEBUG_INFO=y.\n");
-		free(pf.tevs);
-		*tevs = NULL;
 		return -EBADF;
 	}
 
 #if _ELFUTILS_PREREQ(0, 142)
 	/* Get the call frame information from this dwarf */
-	pf.cfi = dwarf_getcfi(dbg);
+	pf->cfi = dwarf_getcfi(dbg);
 #endif
 
 	off = 0;
-	line_list__init(&pf.lcache);
+	line_list__init(&pf->lcache);
 	/* Loop on CUs (Compilation Unit) */
 	while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&
 	       ret >= 0) {
 		/* Get the DIE(Debugging Information Entry) of this CU */
-		diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
+		diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
 		if (!diep)
 			continue;
 
 		/* Check if target file is included. */
 		if (pp->file)
-			pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
+			pf->fname = cu_find_realpath(&pf->cu_die, pp->file);
 		else
-			pf.fname = NULL;
+			pf->fname = NULL;
 
-		if (!pp->file || pf.fname) {
+		if (!pp->file || pf->fname) {
 			if (pp->function)
-				ret = find_probe_point_by_func(&pf);
+				ret = find_probe_point_by_func(pf);
 			else if (pp->lazy_line)
-				ret = find_probe_point_lazy(NULL, &pf);
+				ret = find_probe_point_lazy(NULL, pf);
 			else {
-				pf.lno = pp->line;
-				ret = find_probe_point_by_line(&pf);
+				pf->lno = pp->line;
+				ret = find_probe_point_by_line(pf);
 			}
 		}
 		off = noff;
 	}
-	line_list__free(&pf.lcache);
+	line_list__free(&pf->lcache);
 	dwarf_end(dbg);
 
-	return (ret < 0) ? ret : pf.ntevs;
+	return ret;
+}
+
+/* Add a found probe point into trace event list */
+static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+	struct trace_event_finder *tf =
+			container_of(pf, struct trace_event_finder, pf);
+	struct probe_trace_event *tev;
+	int ret, i;
+
+	/* Check number of tevs */
+	if (tf->ntevs == tf->max_tevs) {
+		pr_warning("Too many( > %d) probe point found.\n",
+			   tf->max_tevs);
+		return -ERANGE;
+	}
+	tev = &tf->tevs[tf->ntevs++];
+
+	ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
+				     &tev->point);
+	if (ret < 0)
+		return ret;
+
+	pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
+		 tev->point.offset);
+
+	/* Find each argument */
+	tev->nargs = pf->pev->nargs;
+	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
+	if (tev->args == NULL)
+		return -ENOMEM;
+	for (i = 0; i < pf->pev->nargs; i++) {
+		pf->pvar = &pf->pev->args[i];
+		pf->tvar = &tev->args[i];
+		ret = find_variable(sp_die, pf);
+		if (ret != 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/* Find probe_trace_events specified by perf_probe_event from debuginfo */
+int find_probe_trace_events(int fd, struct perf_probe_event *pev,
+			    struct probe_trace_event **tevs, int max_tevs)
+{
+	struct trace_event_finder tf = {
+			.pf = {.pev = pev, .callback = add_probe_trace_event},
+			.max_tevs = max_tevs};
+	int ret;
+
+	/* Allocate result tevs array */
+	*tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
+	if (*tevs == NULL)
+		return -ENOMEM;
+
+	tf.tevs = *tevs;
+	tf.ntevs = 0;
+
+	ret = find_probes(fd, &tf.pf);
+	if (ret < 0) {
+		free(*tevs);
+		*tevs = NULL;
+		return ret;
+	}
+
+	return (ret < 0) ? ret : tf.ntevs;
+}
+
+#define MAX_VAR_LEN 64
+
+/* Collect available variables in this scope */
+static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
+{
+	struct available_var_finder *af = data;
+	struct variable_list *vl;
+	char buf[MAX_VAR_LEN];
+	int tag, ret;
+
+	vl = &af->vls[af->nvls - 1];
+
+	tag = dwarf_tag(die_mem);
+	if (tag == DW_TAG_formal_parameter ||
+	    tag == DW_TAG_variable) {
+		ret = convert_variable_location(die_mem, af->pf.addr,
+						af->pf.fb_ops, NULL);
+		if (ret == 0) {
+			ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
+			if (ret > 0)
+				strlist__add(vl->vars, buf);
+		}
+	}
+
+	if (dwarf_haspc(die_mem, af->pf.addr))
+		return DIE_FIND_CB_CONTINUE;
+	else
+		return DIE_FIND_CB_SIBLING;
+}
+
+/* Add a found vars into available variables list */
+static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+	struct available_var_finder *af =
+			container_of(pf, struct available_var_finder, pf);
+	struct variable_list *vl;
+	Dwarf_Die die_mem;
+	int ret;
+
+	/* Check number of tevs */
+	if (af->nvls == af->max_vls) {
+		pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
+		return -ERANGE;
+	}
+	vl = &af->vls[af->nvls++];
+
+	ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
+				     &vl->point);
+	if (ret < 0)
+		return ret;
+
+	pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,
+		 vl->point.offset);
+
+	/* Find local variables */
+	vl->vars = strlist__new(true, NULL);
+	if (vl->vars == NULL)
+		return -ENOMEM;
+	die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
+
+	if (strlist__empty(vl->vars)) {
+		strlist__delete(vl->vars);
+		vl->vars = NULL;
+	}
+
+	return ret;
+}
+
+/* Find available variables at given probe point */
+int find_available_vars_at(int fd, struct perf_probe_event *pev,
+			   struct variable_list **vls, int max_vls)
+{
+	struct available_var_finder af = {
+			.pf = {.pev = pev, .callback = add_available_vars},
+			.max_vls = max_vls};
+	int ret;
+
+	/* Allocate result vls array */
+	*vls = zalloc(sizeof(struct variable_list) * max_vls);
+	if (*vls == NULL)
+		return -ENOMEM;
+
+	af.vls = *vls;
+	af.nvls = 0;
+
+	ret = find_probes(fd, &af.pf);
+	if (ret < 0) {
+		/* Free vlist for error */
+		while (af.nvls--) {
+			if (af.vls[af.nvls].point.symbol)
+				free(af.vls[af.nvls].point.symbol);
+			if (af.vls[af.nvls].vars)
+				strlist__delete(af.vls[af.nvls].vars);
+		}
+		free(af.vls);
+		*vls = NULL;
+		return ret;
+	}
+
+	return (ret < 0) ? ret : af.nvls;
 }
 
 /* Reverse search */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 4507d51..baffd25 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -25,17 +25,22 @@ extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
 extern int find_perf_probe_point(int fd, unsigned long addr,
 				 struct perf_probe_point *ppt);
 
+/* Find a line range */
 extern int find_line_range(int fd, struct line_range *lr);
 
+/* Find available variables */
+extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
+				  struct variable_list **vls, int max_points);
+
 #include <dwarf.h>
 #include <libdw.h>
 #include <version.h>
 
 struct probe_finder {
 	struct perf_probe_event	*pev;		/* Target probe event */
-	struct probe_trace_event *tevs;		/* Result trace events */
-	int			ntevs;		/* Number of trace events */
-	int			max_tevs;	/* Max number of trace events */
+
+	/* Callback when a probe point is found */
+	int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf);
 
 	/* For function searching */
 	int			lno;		/* Line number */
@@ -53,6 +58,20 @@ struct probe_finder {
 	struct probe_trace_arg	*tvar;		/* Current result variable */
 };
 
+struct trace_event_finder {
+	struct probe_finder	pf;
+	struct probe_trace_event *tevs;		/* Found trace events */
+	int			ntevs;		/* Number of trace events */
+	int			max_tevs;	/* Max number of trace events */
+};
+
+struct available_var_finder {
+	struct probe_finder	pf;
+	struct variable_list	*vls;		/* Found variable lists */
+	int			nvls;		/* Number of variable lists */
+	int			max_vls;	/* Max no. of variable lists */
+};
+
 struct line_finder {
 	struct line_range	*lr;		/* Target line range */
 


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

* [PATCH -tip  5/7] perf probe: Function style fix
  2010-10-21 10:12 [PATCH -tip 0/7] Perf probe update (--vars/--module) Masami Hiramatsu
                   ` (3 preceding siblings ...)
  2010-10-21 10:13 ` [PATCH -tip 4/7] perf probe: Show accessible local variables Masami Hiramatsu
@ 2010-10-21 10:13 ` Masami Hiramatsu
  2010-10-23 19:41   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
  2010-10-21 10:13 ` [PATCH -tip 6/7] perf probe: Show accessible global variables Masami Hiramatsu
  2010-10-21 10:13 ` [PATCH -tip 7/7] perf probe: Add basic module support Masami Hiramatsu
  6 siblings, 1 reply; 18+ messages in thread
From: Masami Hiramatsu @ 2010-10-21 10:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, linux-kernel, 2nddept-manager,
	Masami Hiramatsu, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo, Frederic Weisbecker, linux-kernel

Just change the order of function arguments for ease of read;
moving optional bool flag to the last.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: linux-kernel@vger.kernel.org
---

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

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 91bb6cf..c777bec 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -305,8 +305,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 
 	if (params.nevents) {
 		ret = add_perf_probe_events(params.events, params.nevents,
-					    params.force_add,
-					    params.max_probe_points);
+					    params.max_probe_points,
+					    params.force_add);
 		if (ret < 0) {
 			pr_err("  Error: Failed to add events. (%d)\n", ret);
 			return ret;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 3de265e..cafddc9 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1668,7 +1668,7 @@ struct __event_package {
 };
 
 int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
-			  bool force_add, int max_tevs)
+			  int max_tevs, bool force_add)
 {
 	int i, j, ret;
 	struct __event_package *pkgs;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 727a7fe..83130f6 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -117,7 +117,7 @@ extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
 
 
 extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
-				 bool force_add, int max_probe_points);
+				 int max_probe_points, bool force_add);
 extern int del_perf_probe_events(struct strlist *dellist);
 extern int show_perf_probe_events(void);
 extern int show_line_range(struct line_range *lr);


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

* [PATCH -tip  6/7] perf probe: Show accessible global variables
  2010-10-21 10:12 [PATCH -tip 0/7] Perf probe update (--vars/--module) Masami Hiramatsu
                   ` (4 preceding siblings ...)
  2010-10-21 10:13 ` [PATCH -tip 5/7] perf probe: Function style fix Masami Hiramatsu
@ 2010-10-21 10:13 ` Masami Hiramatsu
  2010-10-21 20:50   ` Arnaldo Carvalho de Melo
  2010-10-23 19:42   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
  2010-10-21 10:13 ` [PATCH -tip 7/7] perf probe: Add basic module support Masami Hiramatsu
  6 siblings, 2 replies; 18+ messages in thread
From: Masami Hiramatsu @ 2010-10-21 10:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, linux-kernel, 2nddept-manager,
	Masami Hiramatsu, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo, Frederic Weisbecker, linux-kernel

Add --externs for allowing --vars to show accessible
global(externally defined) variables from a given probe
point too.
This will give you a hint which globals can be accessible
from the probe point.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: linux-kernel@vger.kernel.org
---

 tools/perf/Documentation/perf-probe.txt |    6 +++++-
 tools/perf/builtin-probe.c              |    8 ++++++--
 tools/perf/util/probe-event.c           |    8 ++++----
 tools/perf/util/probe-event.h           |    2 +-
 tools/perf/util/probe-finder.c          |   26 +++++++++++++++++++++-----
 tools/perf/util/probe-finder.h          |    5 ++++-
 6 files changed, 41 insertions(+), 14 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 72f5d9e..148c178 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -18,7 +18,7 @@ or
 or
 'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
 or
-'perf probe' --vars='PROBEPOINT'
+'perf probe' [--externs] --vars='PROBEPOINT'
 
 DESCRIPTION
 -----------
@@ -64,6 +64,10 @@ OPTIONS
 	Show available local variables at given probe point. The argument
 	syntax is same as PROBE SYNTAX, but NO ARGs.
 
+--externs::
+	(Only for --vars) Show external defined variables in addition to local
+	variables.
+
 -f::
 --force::
 	Forcibly add events with existing name.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index c777bec..bdf60cf 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -51,6 +51,7 @@ static struct {
 	bool force_add;
 	bool show_lines;
 	bool show_vars;
+	bool show_ext_vars;
 	bool mod_events;
 	int nevents;
 	struct perf_probe_event events[MAX_PROBES];
@@ -162,7 +163,7 @@ static const char * const probe_usage[] = {
 	"perf probe --list",
 #ifdef DWARF_SUPPORT
 	"perf probe --line 'LINEDESC'",
-	"perf probe --vars 'PROBEPOINT'",
+	"perf probe [--externs] --vars 'PROBEPOINT'",
 #endif
 	NULL
 };
@@ -207,6 +208,8 @@ static const struct option options[] = {
 	OPT_CALLBACK('V', "vars", NULL,
 		     "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
 		     "Show accessible variables on PROBEDEF", opt_show_vars),
+	OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
+		    "Show external variables too (with --vars only)"),
 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 		   "file", "vmlinux pathname"),
 	OPT_STRING('s', "source", &symbol_conf.source_prefix,
@@ -287,7 +290,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			usage_with_options(probe_usage, options);
 		}
 		ret = show_available_vars(params.events, params.nevents,
-					  params.max_probe_points);
+					  params.max_probe_points,
+					  params.show_ext_vars);
 		if (ret < 0)
 			pr_err("  Error: Failed to show vars. (%d)\n", ret);
 		return ret;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index cafddc9..1b462cc 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -379,7 +379,7 @@ end:
 }
 
 static int show_available_vars_at(int fd, struct perf_probe_event *pev,
-				  int max_vls)
+				  int max_vls, bool externs)
 {
 	char *buf;
 	int ret, i;
@@ -391,7 +391,7 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
 		return -EINVAL;
 	pr_debug("Searching variables at %s\n", buf);
 
-	ret = find_available_vars_at(fd, pev, &vls, max_vls);
+	ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
 	if (ret > 0) {
 		/* Some variables are found */
 		fprintf(stdout, "Available variables at %s\n", buf);
@@ -421,7 +421,7 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
 
 /* Show available variables on given probe point */
 int show_available_vars(struct perf_probe_event *pevs, int npevs,
-			int max_vls)
+			int max_vls, bool externs)
 {
 	int i, fd, ret = 0;
 
@@ -438,7 +438,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
 	setup_pager();
 
 	for (i = 0; i < npevs && ret >= 0; i++)
-		ret = show_available_vars_at(fd, &pevs[i], max_vls);
+		ret = show_available_vars_at(fd, &pevs[i], max_vls, externs);
 
 	close(fd);
 	return ret;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 83130f6..c74b1fd 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -122,7 +122,7 @@ extern int del_perf_probe_events(struct strlist *dellist);
 extern int show_perf_probe_events(void);
 extern int show_line_range(struct line_range *lr);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
-			       int max_probe_points);
+			       int max_probe_points, bool externs);
 
 
 /* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 986027f..a274fd0 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -1312,12 +1312,13 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
 						af->pf.fb_ops, NULL);
 		if (ret == 0) {
 			ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
+			pr_debug2("Add new var: %s\n", buf);
 			if (ret > 0)
 				strlist__add(vl->vars, buf);
 		}
 	}
 
-	if (dwarf_haspc(die_mem, af->pf.addr))
+	if (af->child && dwarf_haspc(die_mem, af->pf.addr))
 		return DIE_FIND_CB_CONTINUE;
 	else
 		return DIE_FIND_CB_SIBLING;
@@ -1329,8 +1330,8 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
 	struct available_var_finder *af =
 			container_of(pf, struct available_var_finder, pf);
 	struct variable_list *vl;
-	Dwarf_Die die_mem;
-	int ret;
+	Dwarf_Die die_mem, *scopes = NULL;
+	int ret, nscopes;
 
 	/* Check number of tevs */
 	if (af->nvls == af->max_vls) {
@@ -1351,8 +1352,22 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
 	vl->vars = strlist__new(true, NULL);
 	if (vl->vars == NULL)
 		return -ENOMEM;
+	af->child = true;
 	die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
 
+	/* Find external variables */
+	if (!af->externs)
+		goto out;
+	/* Don't need to search child DIE for externs. */
+	af->child = false;
+	nscopes = dwarf_getscopes_die(sp_die, &scopes);
+	while (nscopes-- > 1)
+		die_find_child(&scopes[nscopes], collect_variables_cb,
+			       (void *)af, &die_mem);
+	if (scopes)
+		free(scopes);
+
+out:
 	if (strlist__empty(vl->vars)) {
 		strlist__delete(vl->vars);
 		vl->vars = NULL;
@@ -1363,11 +1378,12 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
 
 /* Find available variables at given probe point */
 int find_available_vars_at(int fd, struct perf_probe_event *pev,
-			   struct variable_list **vls, int max_vls)
+			   struct variable_list **vls, int max_vls,
+			   bool externs)
 {
 	struct available_var_finder af = {
 			.pf = {.pev = pev, .callback = add_available_vars},
-			.max_vls = max_vls};
+			.max_vls = max_vls, .externs = externs};
 	int ret;
 
 	/* Allocate result vls array */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index baffd25..516912a 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -30,7 +30,8 @@ extern int find_line_range(int fd, struct line_range *lr);
 
 /* Find available variables */
 extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
-				  struct variable_list **vls, int max_points);
+				  struct variable_list **vls, int max_points,
+				  bool externs);
 
 #include <dwarf.h>
 #include <libdw.h>
@@ -70,6 +71,8 @@ struct available_var_finder {
 	struct variable_list	*vls;		/* Found variable lists */
 	int			nvls;		/* Number of variable lists */
 	int			max_vls;	/* Max no. of variable lists */
+	bool			externs;	/* Find external vars too */
+	bool			child;		/* Search child scopes */
 };
 
 struct line_finder {


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

* [PATCH -tip  7/7] perf probe: Add basic module support
  2010-10-21 10:12 [PATCH -tip 0/7] Perf probe update (--vars/--module) Masami Hiramatsu
                   ` (5 preceding siblings ...)
  2010-10-21 10:13 ` [PATCH -tip 6/7] perf probe: Show accessible global variables Masami Hiramatsu
@ 2010-10-21 10:13 ` Masami Hiramatsu
  2010-10-23 19:42   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
  6 siblings, 1 reply; 18+ messages in thread
From: Masami Hiramatsu @ 2010-10-21 10:13 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Ingo Molnar
  Cc: Steven Rostedt, Srikar Dronamraju, linux-kernel, 2nddept-manager,
	Masami Hiramatsu, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo, Frederic Weisbecker, linux-kernel

Add basic module probe support on perf probe. This introduces
"--module <MODNAME>" option to perf probe for putting probes
and showing lines and variables in the given module.

Currently, this supports only probing on running modules.
Supporting off-line module probing is the next step.

e.g.)
[show lines]
 # ./perf probe --module drm -L drm_vblank_info
<drm_vblank_info:0>
      0  int drm_vblank_info(struct seq_file *m, void *data)
      1  {
                struct drm_info_node *node = (struct drm_info_node *) m->private
      3         struct drm_device *dev = node->minor->dev;
 ...
[show vars]
 # ./perf probe --module drm -V drm_vblank_info:3
Available variables at drm_vblank_info:3
        @<drm_vblank_info+20>
                (unknown_type)  data
                struct drm_info_node*   node
                struct seq_file*        m
[put a probe]
 # ./perf probe --module drm drm_vblank_info:3 node m
Add new event:
  probe:drm_vblank_info (on drm_vblank_info:3 with node m)

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

        perf record -e probe:drm_vblank_info -aR sleep 1
[list probes]
 # ./perf probe -l
probe:drm_vblank_info (on drm_vblank_info:3@drivers/gpu/drm/drm_info.c with ...

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: linux-kernel@vger.kernel.org
---

 tools/perf/Documentation/perf-probe.txt |    9 ++
 tools/perf/builtin-probe.c              |   11 ++
 tools/perf/util/map.h                   |   10 ++
 tools/perf/util/probe-event.c           |  123 +++++++++++++++++----------
 tools/perf/util/probe-event.h           |   10 ++
 tools/perf/util/probe-finder.c          |  142 ++++++++++++++++++++++++++++---
 tools/perf/util/probe-finder.h          |    3 -
 7 files changed, 239 insertions(+), 69 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 148c178..62de1b7 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -16,9 +16,9 @@ or
 or
 'perf probe' --list
 or
-'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
+'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
 or
-'perf probe' [--externs] --vars='PROBEPOINT'
+'perf probe' [options] --vars='PROBEPOINT'
 
 DESCRIPTION
 -----------
@@ -33,6 +33,11 @@ OPTIONS
 --vmlinux=PATH::
 	Specify vmlinux path which has debuginfo (Dwarf binary).
 
+-m::
+--module=MODNAME::
+	Specify module name in which perf-probe searches probe points
+	or lines.
+
 -s::
 --source=PATH::
 	Specify path to kernel source.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index bdf60cf..2e000c0 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -57,6 +57,7 @@ static struct {
 	struct perf_probe_event events[MAX_PROBES];
 	struct strlist *dellist;
 	struct line_range line_range;
+	const char *target_module;
 	int max_probe_points;
 } params;
 
@@ -162,8 +163,8 @@ static const char * const probe_usage[] = {
 	"perf probe [<options>] --del '[GROUP:]EVENT' ...",
 	"perf probe --list",
 #ifdef DWARF_SUPPORT
-	"perf probe --line 'LINEDESC'",
-	"perf probe [--externs] --vars 'PROBEPOINT'",
+	"perf probe [<options>] --line 'LINEDESC'",
+	"perf probe [<options>] --vars 'PROBEPOINT'",
 #endif
 	NULL
 };
@@ -214,6 +215,8 @@ static const struct option options[] = {
 		   "file", "vmlinux pathname"),
 	OPT_STRING('s', "source", &symbol_conf.source_prefix,
 		   "directory", "path to kernel source"),
+	OPT_STRING('m', "module", &params.target_module,
+		   "modname", "target module name"),
 #endif
 	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -278,7 +281,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			usage_with_options(probe_usage, options);
 		}
 
-		ret = show_line_range(&params.line_range);
+		ret = show_line_range(&params.line_range, params.target_module);
 		if (ret < 0)
 			pr_err("  Error: Failed to show lines. (%d)\n", ret);
 		return ret;
@@ -291,6 +294,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		}
 		ret = show_available_vars(params.events, params.nevents,
 					  params.max_probe_points,
+					  params.target_module,
 					  params.show_ext_vars);
 		if (ret < 0)
 			pr_err("  Error: Failed to show vars. (%d)\n", ret);
@@ -310,6 +314,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 	if (params.nevents) {
 		ret = add_perf_probe_events(params.events, params.nevents,
 					    params.max_probe_points,
+					    params.target_module,
 					    params.force_add);
 		if (ret < 0) {
 			pr_err("  Error: Failed to add events. (%d)\n", ret);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 7857579..b397c03 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -215,6 +215,16 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *self,
 	return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
 }
 
+static inline
+struct symbol *machine__find_kernel_function_by_name(struct machine *self,
+						     const char *name,
+						     struct map **mapp,
+						     symbol_filter_t filter)
+{
+	return map_groups__find_function_by_name(&self->kmaps, name, mapp,
+						 filter);
+}
+
 int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
 				   int verbose, FILE *fp);
 
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1b462cc..79ef201 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -74,10 +74,9 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
 static struct machine machine;
 
-/* Initialize symbol maps and path of vmlinux */
+/* Initialize symbol maps and path of vmlinux/modules */
 static int init_vmlinux(void)
 {
-	struct dso *kernel;
 	int ret;
 
 	symbol_conf.sort_by_name = true;
@@ -91,33 +90,61 @@ static int init_vmlinux(void)
 		goto out;
 	}
 
-	ret = machine__init(&machine, "/", 0);
+	ret = machine__init(&machine, "", HOST_KERNEL_ID);
 	if (ret < 0)
 		goto out;
 
-	kernel = dso__new_kernel(symbol_conf.vmlinux_name);
-	if (kernel == NULL)
-		die("Failed to create kernel dso.");
-
-	ret = __machine__create_kernel_maps(&machine, kernel);
-	if (ret < 0)
-		pr_debug("Failed to create kernel maps.\n");
-
+	if (machine__create_kernel_maps(&machine) < 0) {
+		pr_debug("machine__create_kernel_maps ");
+		goto out;
+	}
 out:
 	if (ret < 0)
 		pr_warning("Failed to init vmlinux path.\n");
 	return ret;
 }
 
+static struct symbol *__find_kernel_function_by_name(const char *name,
+						     struct map **mapp)
+{
+	return machine__find_kernel_function_by_name(&machine, name, mapp,
+						     NULL);
+}
+
+const char *kernel_get_module_path(const char *module)
+{
+	struct dso *dso;
+
+	if (module) {
+		list_for_each_entry(dso, &machine.kernel_dsos, node) {
+			if (strncmp(dso->short_name + 1, module,
+				    dso->short_name_len - 2) == 0)
+				goto found;
+		}
+		pr_debug("Failed to find module %s.\n", module);
+		return NULL;
+	} else {
+		dso = machine.vmlinux_maps[MAP__FUNCTION]->dso;
+		if (dso__load_vmlinux_path(dso,
+			 machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
+			pr_debug("Failed to load kernel map.\n");
+			return NULL;
+		}
+	}
+found:
+	return dso->long_name;
+}
+
 #ifdef DWARF_SUPPORT
-static int open_vmlinux(void)
+static int open_vmlinux(const char *module)
 {
-	if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
-		pr_debug("Failed to load kernel map.\n");
-		return -EINVAL;
+	const char *path = kernel_get_module_path(module);
+	if (!path) {
+		pr_err("Failed to find path of %s module", module ?: "kernel");
+		return -ENOENT;
 	}
-	pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name);
-	return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
+	pr_debug("Try to open %s\n", path);
+	return open(path, O_RDONLY);
 }
 
 /*
@@ -125,20 +152,19 @@ static int open_vmlinux(void)
  * Currently only handles kprobes.
  */
 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-				       struct perf_probe_point *pp)
+					struct perf_probe_point *pp)
 {
 	struct symbol *sym;
-	int fd, ret = -ENOENT;
+	struct map *map;
+	u64 addr;
+	int ret = -ENOENT;
 
-	sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
-				       tp->symbol, NULL);
+	sym = __find_kernel_function_by_name(tp->symbol, &map);
 	if (sym) {
-		fd = open_vmlinux();
-		if (fd >= 0) {
-			ret = find_perf_probe_point(fd,
-						 sym->start + tp->offset, pp);
-			close(fd);
-		}
+		addr = map->unmap_ip(map, sym->start + tp->offset);
+		pr_debug("try to find %s+%ld@%llx\n", tp->symbol,
+			 tp->offset, addr);
+		ret = find_perf_probe_point((unsigned long)addr, pp);
 	}
 	if (ret <= 0) {
 		pr_debug("Failed to find corresponding probes from "
@@ -156,12 +182,12 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 /* Try to find perf_probe_event with debuginfo */
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 					   struct probe_trace_event **tevs,
-					   int max_tevs)
+					   int max_tevs, const char *module)
 {
 	bool need_dwarf = perf_probe_event_need_dwarf(pev);
 	int fd, ntevs;
 
-	fd = open_vmlinux();
+	fd = open_vmlinux(module);
 	if (fd < 0) {
 		if (need_dwarf) {
 			pr_warning("Failed to open debuginfo file.\n");
@@ -300,7 +326,7 @@ error:
  * Show line-range always requires debuginfo to find source file and
  * line number.
  */
-int show_line_range(struct line_range *lr)
+int show_line_range(struct line_range *lr, const char *module)
 {
 	int l = 1;
 	struct line_node *ln;
@@ -313,7 +339,7 @@ int show_line_range(struct line_range *lr)
 	if (ret < 0)
 		return ret;
 
-	fd = open_vmlinux();
+	fd = open_vmlinux(module);
 	if (fd < 0) {
 		pr_warning("Failed to open debuginfo file.\n");
 		return fd;
@@ -421,7 +447,7 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
 
 /* Show available variables on given probe point */
 int show_available_vars(struct perf_probe_event *pevs, int npevs,
-			int max_vls, bool externs)
+			int max_vls, const char *module, bool externs)
 {
 	int i, fd, ret = 0;
 
@@ -429,7 +455,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
 	if (ret < 0)
 		return ret;
 
-	fd = open_vmlinux();
+	fd = open_vmlinux(module);
 	if (fd < 0) {
 		pr_warning("Failed to open debuginfo file.\n");
 		return fd;
@@ -447,8 +473,15 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
 #else	/* !DWARF_SUPPORT */
 
 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-				       struct perf_probe_point *pp)
+					struct perf_probe_point *pp)
 {
+	struct symbol *sym;
+
+	sym = __find_kernel_function_by_name(tp->symbol, NULL);
+	if (!sym) {
+		pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
+		return -ENOENT;
+	}
 	pp->function = strdup(tp->symbol);
 	if (pp->function == NULL)
 		return -ENOMEM;
@@ -460,7 +493,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 				struct probe_trace_event **tevs __unused,
-				int max_tevs __unused)
+				int max_tevs __unused, const char *mod __unused)
 {
 	if (perf_probe_event_need_dwarf(pev)) {
 		pr_warning("Debuginfo-analysis is not supported.\n");
@@ -469,14 +502,15 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 	return 0;
 }
 
-int show_line_range(struct line_range *lr __unused)
+int show_line_range(struct line_range *lr __unused, const char *module __unused)
 {
 	pr_warning("Debuginfo-analysis is not supported.\n");
 	return -ENOSYS;
 }
 
 int show_available_vars(struct perf_probe_event *pevs __unused,
-			int npevs __unused, int max_probe_points __unused)
+			int npevs __unused, int max_vls __unused,
+			const char *module __unused, bool externs __unused)
 {
 	pr_warning("Debuginfo-analysis is not supported.\n");
 	return -ENOSYS;
@@ -1159,7 +1193,7 @@ error:
 }
 
 static int convert_to_perf_probe_event(struct probe_trace_event *tev,
-				struct perf_probe_event *pev)
+				       struct perf_probe_event *pev)
 {
 	char buf[64] = "";
 	int i, ret;
@@ -1588,14 +1622,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 
 static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 					  struct probe_trace_event **tevs,
-					  int max_tevs)
+					  int max_tevs, const char *module)
 {
 	struct symbol *sym;
 	int ret = 0, i;
 	struct probe_trace_event *tev;
 
 	/* Convert perf_probe_event with debuginfo */
-	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs);
+	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
 	if (ret != 0)
 		return ret;
 
@@ -1644,8 +1678,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 	}
 
 	/* Currently just checking function name from symbol map */
-	sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
-				       tev->point.symbol, NULL);
+	sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
 	if (!sym) {
 		pr_warning("Kernel symbol \'%s\' not found.\n",
 			   tev->point.symbol);
@@ -1668,7 +1701,7 @@ struct __event_package {
 };
 
 int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
-			  int max_tevs, bool force_add)
+			  int max_tevs, const char *module, bool force_add)
 {
 	int i, j, ret;
 	struct __event_package *pkgs;
@@ -1689,7 +1722,9 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
 		pkgs[i].pev = &pevs[i];
 		/* Convert with or without debuginfo */
 		ret  = convert_to_probe_trace_events(pkgs[i].pev,
-						      &pkgs[i].tevs, max_tevs);
+						     &pkgs[i].tevs,
+						     max_tevs,
+						     module);
 		if (ret < 0)
 			goto end;
 		pkgs[i].ntevs = ret;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index c74b1fd..5accbed 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -115,14 +115,18 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev);
 /* Command string to line-range */
 extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
 
+/* Internal use: Return kernel/module path */
+extern const char *kernel_get_module_path(const char *module);
 
 extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
-				 int max_probe_points, bool force_add);
+				 int max_probe_points, const char *module,
+				 bool force_add);
 extern int del_perf_probe_events(struct strlist *dellist);
 extern int show_perf_probe_events(void);
-extern int show_line_range(struct line_range *lr);
+extern int show_line_range(struct line_range *lr, const char *module);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
-			       int max_probe_points, bool externs);
+			       int max_probe_points, const char *module,
+			       bool externs);
 
 
 /* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index a274fd0..c20bd52 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -116,6 +116,101 @@ static void line_list__free(struct list_head *head)
 	}
 }
 
+/* Dwarf FL wrappers */
+
+static int __linux_kernel_find_elf(Dwfl_Module *mod,
+				   void **userdata,
+				   const char *module_name,
+				   Dwarf_Addr base,
+				   char **file_name, Elf **elfp)
+{
+	int fd;
+	const char *path = kernel_get_module_path(module_name);
+
+	if (path) {
+		fd = open(path, O_RDONLY);
+		if (fd >= 0) {
+			*file_name = strdup(path);
+			return fd;
+		}
+	}
+	/* If failed, try to call standard method */
+	return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
+					  file_name, elfp);
+}
+
+static char *debuginfo_path;	/* Currently dummy */
+
+static const Dwfl_Callbacks offline_callbacks = {
+	.find_debuginfo = dwfl_standard_find_debuginfo,
+	.debuginfo_path = &debuginfo_path,
+
+	.section_address = dwfl_offline_section_address,
+
+	/* We use this table for core files too.  */
+	.find_elf = dwfl_build_id_find_elf,
+};
+
+static const Dwfl_Callbacks kernel_callbacks = {
+	.find_debuginfo = dwfl_standard_find_debuginfo,
+	.debuginfo_path = &debuginfo_path,
+
+	.find_elf = __linux_kernel_find_elf,
+	.section_address = dwfl_linux_kernel_module_section_address,
+};
+
+/* Get a Dwarf from offline image */
+static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
+{
+	Dwfl_Module *mod;
+	Dwarf *dbg = NULL;
+
+	if (!dwflp)
+		return NULL;
+
+	*dwflp = dwfl_begin(&offline_callbacks);
+	if (!*dwflp)
+		return NULL;
+
+	mod = dwfl_report_offline(*dwflp, "", "", fd);
+	if (!mod)
+		goto error;
+
+	dbg = dwfl_module_getdwarf(mod, bias);
+	if (!dbg) {
+error:
+		dwfl_end(*dwflp);
+		*dwflp = NULL;
+	}
+	return dbg;
+}
+
+/* Get a Dwarf from live kernel image */
+static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
+					  Dwarf_Addr *bias)
+{
+	Dwarf *dbg;
+
+	if (!dwflp)
+		return NULL;
+
+	*dwflp = dwfl_begin(&kernel_callbacks);
+	if (!*dwflp)
+		return NULL;
+
+	/* Load the kernel dwarves: Don't care the result here */
+	dwfl_linux_kernel_report_kernel(*dwflp);
+	dwfl_linux_kernel_report_modules(*dwflp);
+
+	dbg = dwfl_addrdwarf(*dwflp, addr, bias);
+	/* Here, check whether we could get a real dwarf */
+	if (!dbg) {
+		dwfl_end(*dwflp);
+		*dwflp = NULL;
+	}
+	return dbg;
+}
+
 /* Dwarf wrappers */
 
 /* Find the realpath of the target file. */
@@ -1177,10 +1272,12 @@ static int find_probes(int fd, struct probe_finder *pf)
 	Dwarf_Off off, noff;
 	size_t cuhl;
 	Dwarf_Die *diep;
-	Dwarf *dbg;
+	Dwarf *dbg = NULL;
+	Dwfl *dwfl;
+	Dwarf_Addr bias;	/* Currently ignored */
 	int ret = 0;
 
-	dbg = dwarf_begin(fd, DWARF_C_READ);
+	dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
 	if (!dbg) {
 		pr_warning("No dwarf info found in the vmlinux - "
 			"please rebuild with CONFIG_DEBUG_INFO=y.\n");
@@ -1221,7 +1318,8 @@ static int find_probes(int fd, struct probe_finder *pf)
 		off = noff;
 	}
 	line_list__free(&pf->lcache);
-	dwarf_end(dbg);
+	if (dwfl)
+		dwfl_end(dwfl);
 
 	return ret;
 }
@@ -1412,23 +1510,31 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev,
 }
 
 /* Reverse search */
-int find_perf_probe_point(int fd, unsigned long addr,
-			  struct perf_probe_point *ppt)
+int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
 {
 	Dwarf_Die cudie, spdie, indie;
-	Dwarf *dbg;
+	Dwarf *dbg = NULL;
+	Dwfl *dwfl = NULL;
 	Dwarf_Line *line;
-	Dwarf_Addr laddr, eaddr;
+	Dwarf_Addr laddr, eaddr, bias = 0;
 	const char *tmp;
 	int lineno, ret = 0;
 	bool found = false;
 
-	dbg = dwarf_begin(fd, DWARF_C_READ);
-	if (!dbg)
-		return -EBADF;
+	/* Open the live linux kernel */
+	dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
+	if (!dbg) {
+		pr_warning("No dwarf info found in the vmlinux - "
+			"please rebuild with CONFIG_DEBUG_INFO=y.\n");
+		ret = -EINVAL;
+		goto end;
+	}
 
+	/* Adjust address with bias */
+	addr += bias;
 	/* Find cu die */
-	if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) {
+	if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
+		pr_warning("No CU DIE is found at %lx\n", addr);
 		ret = -EINVAL;
 		goto end;
 	}
@@ -1491,7 +1597,8 @@ found:
 	}
 
 end:
-	dwarf_end(dbg);
+	if (dwfl)
+		dwfl_end(dwfl);
 	if (ret >= 0)
 		ret = found ? 1 : 0;
 	return ret;
@@ -1624,6 +1731,8 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
 	struct line_finder *lf = param->data;
 	struct line_range *lr = lf->lr;
 
+	pr_debug("find (%lx) %s\n", dwarf_dieoffset(sp_die),
+		 dwarf_diename(sp_die));
 	if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
 	    die_compare_name(sp_die, lr->function)) {
 		lf->fname = dwarf_decl_file(sp_die);
@@ -1667,10 +1776,12 @@ int find_line_range(int fd, struct line_range *lr)
 	Dwarf_Off off = 0, noff;
 	size_t cuhl;
 	Dwarf_Die *diep;
-	Dwarf *dbg;
+	Dwarf *dbg = NULL;
+	Dwfl *dwfl;
+	Dwarf_Addr bias;	/* Currently ignored */
 	const char *comp_dir;
 
-	dbg = dwarf_begin(fd, DWARF_C_READ);
+	dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
 	if (!dbg) {
 		pr_warning("No dwarf info found in the vmlinux - "
 			"please rebuild with CONFIG_DEBUG_INFO=y.\n");
@@ -1716,8 +1827,7 @@ int find_line_range(int fd, struct line_range *lr)
 	}
 
 	pr_debug("path: %s\n", lr->path);
-	dwarf_end(dbg);
-
+	dwfl_end(dwfl);
 	return (ret < 0) ? ret : lf.found;
 }
 
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 516912a..bba69d4 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -22,7 +22,7 @@ extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
 				    int max_tevs);
 
 /* Find a perf_probe_point from debuginfo */
-extern int find_perf_probe_point(int fd, unsigned long addr,
+extern int find_perf_probe_point(unsigned long addr,
 				 struct perf_probe_point *ppt);
 
 /* Find a line range */
@@ -35,6 +35,7 @@ extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
 
 #include <dwarf.h>
 #include <libdw.h>
+#include <libdwfl.h>
 #include <version.h>
 
 struct probe_finder {


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

* Re: [PATCH -tip  6/7] perf probe: Show accessible global variables
  2010-10-21 10:13 ` [PATCH -tip 6/7] perf probe: Show accessible global variables Masami Hiramatsu
@ 2010-10-21 20:50   ` Arnaldo Carvalho de Melo
  2010-10-22  2:25     ` Masami Hiramatsu
  2010-10-23 19:42   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
  1 sibling, 1 reply; 18+ messages in thread
From: Arnaldo Carvalho de Melo @ 2010-10-21 20:50 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Ingo Molnar, Steven Rostedt, Srikar Dronamraju, linux-kernel,
	2nddept-manager, Peter Zijlstra, Paul Mackerras,
	Frederic Weisbecker

Em Thu, Oct 21, 2010 at 07:13:35PM +0900, Masami Hiramatsu escreveu:
> Add --externs for allowing --vars to show accessible
> global(externally defined) variables from a given probe
> point too.
> This will give you a hint which globals can be accessible
> from the probe point.

Cool, but perhaps we need to filter out some of the globals? Things
like:

                long unsigned int       __kcrctab_tcp_hashinfo
                long unsigned int       __kcrctab_tcp_proc_register
                long unsigned int       __kcrctab_tcp_proc_unregister
                long unsigned int       __kcrctab_tcp_prot

If --verbose is specified we could then show everything.

So that it doesn't get this long:

[root@emilia ~]# perf probe -V tcp_v4_do_rcv:28 --externs
Available variables at tcp_v4_do_rcv:28
	@<tcp_v4_do_rcv+390>
		(function_type)*	ip_nat_decode_session
		(unknown_type)	__crc_ipv4_specific
		(unknown_type)	__crc_sysctl_tcp_low_latency
		(unknown_type)	__crc_tcp4_gro_complete
		(unknown_type)	__crc_tcp4_gro_receive
		(unknown_type)	__crc_tcp_hashinfo
		(unknown_type)	__crc_tcp_proc_register
		(unknown_type)	__crc_tcp_proc_unregister
		(unknown_type)	__crc_tcp_prot
		(unknown_type)	__crc_tcp_twsk_unique
		(unknown_type)	__crc_tcp_v4_conn_request
		(unknown_type)	__crc_tcp_v4_connect
		(unknown_type)	__crc_tcp_v4_destroy_sock
		(unknown_type)	__crc_tcp_v4_do_rcv
		(unknown_type)	__crc_tcp_v4_md5_do_add
		(unknown_type)	__crc_tcp_v4_md5_do_del
		(unknown_type)	__crc_tcp_v4_md5_hash_skb
		(unknown_type)	__crc_tcp_v4_md5_lookup
		(unknown_type)	__crc_tcp_v4_remember_stamp
		(unknown_type)	__crc_tcp_v4_send_check
		(unknown_type)	__crc_tcp_v4_syn_recv_sock
		__u8*	ip_tos2prio
		atomic_long_t*	vm_stat
		atomic_t	tcp_memory_allocated
		bool	c1e_detected
		char	__pcpu_scope_cpu_core_map
		char	__pcpu_scope_cpu_info
		char	__pcpu_scope_cpu_llc_id
		char	__pcpu_scope_cpu_number
		char	__pcpu_scope_cpu_sibling_map
		char	__pcpu_scope_current_task
		char	__pcpu_scope_init_tss
		char	__pcpu_scope_irq_count
		char	__pcpu_scope_irq_regs
		char	__pcpu_scope_irq_stack_ptr
		char	__pcpu_scope_irq_stack_union
		char	__pcpu_scope_irq_stat
		char	__pcpu_scope_kernel_stack
		char	__pcpu_scope_numa_node
		char	__pcpu_scope_orig_ist
		char	__pcpu_scope_process_counts
		char	__pcpu_scope_softirq_work_list
		char	__pcpu_scope_softnet_data
		char	__pcpu_scope_this_cpu_off
		char	__pcpu_scope_tick_cpu_device
		char	__pcpu_scope_vector_irq
		char	__pcpu_scope_vm_event_states
		char	__pcpu_scope_x2apic_extra_bits
		char	__pcpu_scope_x86_bios_cpu_apicid
		char	__pcpu_scope_x86_cpu_to_apicid
		char	__pcpu_scope_x86_cpu_to_node_map
		char*	__kstrtab_ipv4_specific
		char*	__kstrtab_sysctl_tcp_low_latency
		char*	__kstrtab_tcp4_gro_complete
		char*	__kstrtab_tcp4_gro_receive
		char*	__kstrtab_tcp_hashinfo
		char*	__kstrtab_tcp_proc_register
		char*	__kstrtab_tcp_proc_unregister
		char*	__kstrtab_tcp_prot
		char*	__kstrtab_tcp_twsk_unique
		char*	__kstrtab_tcp_v4_conn_request
		char*	__kstrtab_tcp_v4_connect
		char*	__kstrtab_tcp_v4_destroy_sock
		char*	__kstrtab_tcp_v4_do_rcv
		char*	__kstrtab_tcp_v4_md5_do_add
		char*	__kstrtab_tcp_v4_md5_do_del
		char*	__kstrtab_tcp_v4_md5_hash_skb
		char*	__kstrtab_tcp_v4_md5_lookup
		char*	__kstrtab_tcp_v4_remember_stamp
		char*	__kstrtab_tcp_v4_send_check
		char*	__kstrtab_tcp_v4_syn_recv_sock
		char*	hex_asc
		char*	inet_csk_timer_bug_msg
		cpumask_var_t	cpu_callout_mask
		cpumask_var_t	cpu_core_map
		cpumask_var_t	cpu_sibling_map
		cpumask_var_t*	node_to_cpumask_map
		int	acpi_disabled
		int	acpi_noirq
		int	acpi_pci_disabled
		int	audit_enabled
		int	cpu_number
		int	debug_locks
		int	disable_apic
		int	net_msg_warn
		int	nr_cpu_ids
		int	nr_online_nodes
		int	numa_node
		int	page_group_by_mobility_disabled
		int	percpu_counter_batch
		int	prof_on
		int	sched_mc_power_savings
		int	sched_smt_power_savings
		int	smp_found_config
		int	sysctl_max_syn_backlog
		int	sysctl_tcp_adv_win_scale
		int	sysctl_tcp_cookie_size
		int	sysctl_tcp_ecn
		int	sysctl_tcp_fin_timeout
		int	sysctl_tcp_keepalive_intvl
		int	sysctl_tcp_keepalive_probes
		int	sysctl_tcp_keepalive_time
		int	sysctl_tcp_low_latency
		int	sysctl_tcp_max_orphans
		int	sysctl_tcp_reordering
		int	sysctl_tcp_syncookies
		int	sysctl_tcp_tw_reuse
		int	tcp_memory_pressure
		int	time_status
		int	timer_stats_active
		int	x2apic_phys
		int	x86_cpu_to_node_map
		int*	console_printk
		int*	sysctl_tcp_mem
		int*	sysctl_tcp_rmem
		int*	sysctl_tcp_wmem
		int*	x86_cpu_to_node_map_early_ptr
		irq_cpustat_t	irq_stat
		long unsigned int	__kcrctab_ipv4_specific
		long unsigned int	__kcrctab_sysctl_tcp_low_latency
		long unsigned int	__kcrctab_tcp4_gro_complete
		long unsigned int	__kcrctab_tcp4_gro_receive
		long unsigned int	__kcrctab_tcp_hashinfo
		long unsigned int	__kcrctab_tcp_proc_register
		long unsigned int	__kcrctab_tcp_proc_unregister
		long unsigned int	__kcrctab_tcp_prot
		long unsigned int	__kcrctab_tcp_twsk_unique
		long unsigned int	__kcrctab_tcp_v4_conn_request
		long unsigned int	__kcrctab_tcp_v4_connect
		long unsigned int	__kcrctab_tcp_v4_destroy_sock
		long unsigned int	__kcrctab_tcp_v4_do_rcv
		long unsigned int	__kcrctab_tcp_v4_md5_do_add
		long unsigned int	__kcrctab_tcp_v4_md5_do_del
		long unsigned int	__kcrctab_tcp_v4_md5_hash_skb
		long unsigned int	__kcrctab_tcp_v4_md5_lookup
		long unsigned int	__kcrctab_tcp_v4_remember_stamp
		long unsigned int	__kcrctab_tcp_v4_send_check
		long unsigned int	__kcrctab_tcp_v4_syn_recv_sock
		long unsigned int	jiffies
		long unsigned int	kernel_stack
		long unsigned int	mmap_min_addr
		long unsigned int	mmu_cr4_features
		long unsigned int*	__per_cpu_offset
		long unsigned int*	cpu_bit_bitmap
		long unsigned int*	sysctl_local_reserved_ports
		nodemask_t*	node_states
		pg_data_t**	node_data
		physid_mask_t	phys_cpu_present_map
		pteval_t	__supported_pte_mask
		spinlock_t	dcache_lock
		struct address_space	swapper_space
		struct apic*	apic
		struct cache_sizes*	malloc_sizes
		struct cpuinfo_x86	boot_cpu_data
		struct cpuinfo_x86	cpu_info
		struct cpumask*	cpu_online_mask
		struct cpumask*	cpu_possible_mask
		struct cpumask*	cpu_present_mask
		struct device	x86_dma_fallback_dev
		struct dma_map_ops*	dma_ops
		struct dqstats	dqstats
		struct icmp_err*	icmp_err_convert
		struct inet_connection_sock_af_ops	ipv4_specific
		struct inet_hashinfo	tcp_hashinfo
		struct inet_timewait_death_row	tcp_death_row
		struct kernel_symbol	__ksymtab_ipv4_specific
		struct kernel_symbol	__ksymtab_sysctl_tcp_low_latency
		struct kernel_symbol	__ksymtab_tcp4_gro_complete
		struct kernel_symbol	__ksymtab_tcp4_gro_receive
		struct kernel_symbol	__ksymtab_tcp_hashinfo
		struct kernel_symbol	__ksymtab_tcp_proc_register
		struct kernel_symbol	__ksymtab_tcp_proc_unregister
		struct kernel_symbol	__ksymtab_tcp_prot
		struct kernel_symbol	__ksymtab_tcp_twsk_unique
		struct kernel_symbol	__ksymtab_tcp_v4_conn_request
		struct kernel_symbol	__ksymtab_tcp_v4_connect
		struct kernel_symbol	__ksymtab_tcp_v4_destroy_sock
		struct kernel_symbol	__ksymtab_tcp_v4_do_rcv
		struct kernel_symbol	__ksymtab_tcp_v4_md5_do_add
		struct kernel_symbol	__ksymtab_tcp_v4_md5_do_del
		struct kernel_symbol	__ksymtab_tcp_v4_md5_hash_skb
		struct kernel_symbol	__ksymtab_tcp_v4_md5_lookup
		struct kernel_symbol	__ksymtab_tcp_v4_remember_stamp
		struct kernel_symbol	__ksymtab_tcp_v4_send_check
		struct kernel_symbol	__ksymtab_tcp_v4_syn_recv_sock
		struct list_head*	nf_hooks
		struct mem_section**	mem_section
		struct memnode	memnode
		struct neigh_table	nd_tbl
		struct nf_afinfo**	nf_afinfo
		struct percpu_counter	tcp_orphan_count
		struct percpu_counter	tcp_sockets_allocated
		struct pernet_operations	tcp4_net_ops
		struct pernet_operations	tcp_sk_ops
		struct pglist_data**	node_data
		struct pid*	cad_pid
		struct pid_namespace	init_pid_ns
		struct proto	tcp_prot
		struct pt_regs*	irq_regs
		struct pv_apic_ops	pv_apic_ops
		struct pv_cpu_ops	pv_cpu_ops
		struct pv_info	pv_info
		struct pv_irq_ops	pv_irq_ops
		struct pv_mmu_ops	pv_mmu_ops
		struct pv_time_ops	pv_time_ops
		struct request_sock_ops	tcp_request_sock_ops
		struct resource	ioport_resource
		struct rps_sock_flow_table*	rps_sock_flow_table
		struct sk_buff*	skb
		struct smp_ops	smp_ops
		struct sock*	sk
		struct task_struct*	current_task
		struct tcp_congestion_ops	tcp_init_congestion_ops
		struct tcp_request_sock_ops	tcp_request_sock_ipv4_ops
		struct tcp_seq_afinfo	tcp4_seq_afinfo
		struct tcp_sock_af_ops	tcp_sock_ipv4_specific
		struct timewait_sock_ops	tcp_timewait_sock_ops
		struct tracepoint	__tracepoint_irq_handler_entry
		struct tracepoint	__tracepoint_irq_handler_exit
		struct tracepoint	__tracepoint_kfree
		struct tracepoint	__tracepoint_kmalloc
		struct tracepoint	__tracepoint_kmalloc_node
		struct tracepoint	__tracepoint_kmem_cache_alloc
		struct tracepoint	__tracepoint_kmem_cache_alloc_node
		struct tracepoint	__tracepoint_kmem_cache_free
		struct tracepoint	__tracepoint_mm_page_alloc
		struct tracepoint	__tracepoint_mm_page_alloc_extfrag
		struct tracepoint	__tracepoint_mm_page_alloc_zone_locked
		struct tracepoint	__tracepoint_mm_page_free_direct
		struct tracepoint	__tracepoint_mm_page_pcpu_drain
		struct tracepoint	__tracepoint_mm_pagevec_free
		struct tracepoint	__tracepoint_module_free
		struct tracepoint	__tracepoint_module_get
		struct tracepoint	__tracepoint_module_load
		struct tracepoint	__tracepoint_module_put
		struct tracepoint	__tracepoint_module_request
		struct tracepoint	__tracepoint_softirq_entry
		struct tracepoint	__tracepoint_softirq_exit
		struct tracepoint	__tracepoint_softirq_raise
		struct vm_event_state	vm_event_states
		struct x86_init_ops	x86_init
		struct x86_platform_ops	x86_platform
		u16	x86_bios_cpu_apicid
		u32	inet_ehash_secret
		union irq_stack_union	irq_stack_union
		unsigned int	apic_verbosity
		unsigned int	sysctl_timer_migration

- Arnaldo

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

* Re: [PATCH -tip  6/7] perf probe: Show accessible global variables
  2010-10-21 20:50   ` Arnaldo Carvalho de Melo
@ 2010-10-22  2:25     ` Masami Hiramatsu
  2010-10-22  5:31       ` Masami Hiramatsu
  0 siblings, 1 reply; 18+ messages in thread
From: Masami Hiramatsu @ 2010-10-22  2:25 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ingo Molnar, Steven Rostedt, Srikar Dronamraju, linux-kernel,
	2nddept-manager, Peter Zijlstra, Paul Mackerras,
	Frederic Weisbecker

(2010/10/22 5:50), Arnaldo Carvalho de Melo wrote:
> Em Thu, Oct 21, 2010 at 07:13:35PM +0900, Masami Hiramatsu escreveu:
>> Add --externs for allowing --vars to show accessible
>> global(externally defined) variables from a given probe
>> point too.
>> This will give you a hint which globals can be accessible
>> from the probe point.
> 
> Cool, but perhaps we need to filter out some of the globals? Things
> like:

Hmm, yeah. So is that enough to filter out symbols which start with
__k???tab_ and __crc_ ?


> 
>                 long unsigned int       __kcrctab_tcp_hashinfo
>                 long unsigned int       __kcrctab_tcp_proc_register
>                 long unsigned int       __kcrctab_tcp_proc_unregister
>                 long unsigned int       __kcrctab_tcp_prot
> 
> If --verbose is specified we could then show everything.

--verbose is already used for showing debug messages,  ;)
so how about using --all/--allextras?

Or, perhaps we can add more generic filtering for listing
events/vars/funcs.

Thank you,

> 
> So that it doesn't get this long:
> 
> [root@emilia ~]# perf probe -V tcp_v4_do_rcv:28 --externs
> Available variables at tcp_v4_do_rcv:28
> 	@<tcp_v4_do_rcv+390>
> 		(function_type)*	ip_nat_decode_session
> 		(unknown_type)	__crc_ipv4_specific
> 		(unknown_type)	__crc_sysctl_tcp_low_latency
> 		(unknown_type)	__crc_tcp4_gro_complete
> 		(unknown_type)	__crc_tcp4_gro_receive
> 		(unknown_type)	__crc_tcp_hashinfo
> 		(unknown_type)	__crc_tcp_proc_register
> 		(unknown_type)	__crc_tcp_proc_unregister
> 		(unknown_type)	__crc_tcp_prot
> 		(unknown_type)	__crc_tcp_twsk_unique
> 		(unknown_type)	__crc_tcp_v4_conn_request
> 		(unknown_type)	__crc_tcp_v4_connect
> 		(unknown_type)	__crc_tcp_v4_destroy_sock
> 		(unknown_type)	__crc_tcp_v4_do_rcv
> 		(unknown_type)	__crc_tcp_v4_md5_do_add
> 		(unknown_type)	__crc_tcp_v4_md5_do_del
> 		(unknown_type)	__crc_tcp_v4_md5_hash_skb
> 		(unknown_type)	__crc_tcp_v4_md5_lookup
> 		(unknown_type)	__crc_tcp_v4_remember_stamp
> 		(unknown_type)	__crc_tcp_v4_send_check
> 		(unknown_type)	__crc_tcp_v4_syn_recv_sock
> 		__u8*	ip_tos2prio
> 		atomic_long_t*	vm_stat
> 		atomic_t	tcp_memory_allocated
> 		bool	c1e_detected
> 		char	__pcpu_scope_cpu_core_map
> 		char	__pcpu_scope_cpu_info
> 		char	__pcpu_scope_cpu_llc_id
> 		char	__pcpu_scope_cpu_number
> 		char	__pcpu_scope_cpu_sibling_map
> 		char	__pcpu_scope_current_task
> 		char	__pcpu_scope_init_tss
> 		char	__pcpu_scope_irq_count
> 		char	__pcpu_scope_irq_regs
> 		char	__pcpu_scope_irq_stack_ptr
> 		char	__pcpu_scope_irq_stack_union
> 		char	__pcpu_scope_irq_stat
> 		char	__pcpu_scope_kernel_stack
> 		char	__pcpu_scope_numa_node
> 		char	__pcpu_scope_orig_ist
> 		char	__pcpu_scope_process_counts
> 		char	__pcpu_scope_softirq_work_list
> 		char	__pcpu_scope_softnet_data
> 		char	__pcpu_scope_this_cpu_off
> 		char	__pcpu_scope_tick_cpu_device
> 		char	__pcpu_scope_vector_irq
> 		char	__pcpu_scope_vm_event_states
> 		char	__pcpu_scope_x2apic_extra_bits
> 		char	__pcpu_scope_x86_bios_cpu_apicid
> 		char	__pcpu_scope_x86_cpu_to_apicid
> 		char	__pcpu_scope_x86_cpu_to_node_map
> 		char*	__kstrtab_ipv4_specific
> 		char*	__kstrtab_sysctl_tcp_low_latency
> 		char*	__kstrtab_tcp4_gro_complete
> 		char*	__kstrtab_tcp4_gro_receive
> 		char*	__kstrtab_tcp_hashinfo
> 		char*	__kstrtab_tcp_proc_register
> 		char*	__kstrtab_tcp_proc_unregister
> 		char*	__kstrtab_tcp_prot
> 		char*	__kstrtab_tcp_twsk_unique
> 		char*	__kstrtab_tcp_v4_conn_request
> 		char*	__kstrtab_tcp_v4_connect
> 		char*	__kstrtab_tcp_v4_destroy_sock
> 		char*	__kstrtab_tcp_v4_do_rcv
> 		char*	__kstrtab_tcp_v4_md5_do_add
> 		char*	__kstrtab_tcp_v4_md5_do_del
> 		char*	__kstrtab_tcp_v4_md5_hash_skb
> 		char*	__kstrtab_tcp_v4_md5_lookup
> 		char*	__kstrtab_tcp_v4_remember_stamp
> 		char*	__kstrtab_tcp_v4_send_check
> 		char*	__kstrtab_tcp_v4_syn_recv_sock
> 		char*	hex_asc
> 		char*	inet_csk_timer_bug_msg
> 		cpumask_var_t	cpu_callout_mask
> 		cpumask_var_t	cpu_core_map
> 		cpumask_var_t	cpu_sibling_map
> 		cpumask_var_t*	node_to_cpumask_map
> 		int	acpi_disabled
> 		int	acpi_noirq
> 		int	acpi_pci_disabled
> 		int	audit_enabled
> 		int	cpu_number
> 		int	debug_locks
> 		int	disable_apic
> 		int	net_msg_warn
> 		int	nr_cpu_ids
> 		int	nr_online_nodes
> 		int	numa_node
> 		int	page_group_by_mobility_disabled
> 		int	percpu_counter_batch
> 		int	prof_on
> 		int	sched_mc_power_savings
> 		int	sched_smt_power_savings
> 		int	smp_found_config
> 		int	sysctl_max_syn_backlog
> 		int	sysctl_tcp_adv_win_scale
> 		int	sysctl_tcp_cookie_size
> 		int	sysctl_tcp_ecn
> 		int	sysctl_tcp_fin_timeout
> 		int	sysctl_tcp_keepalive_intvl
> 		int	sysctl_tcp_keepalive_probes
> 		int	sysctl_tcp_keepalive_time
> 		int	sysctl_tcp_low_latency
> 		int	sysctl_tcp_max_orphans
> 		int	sysctl_tcp_reordering
> 		int	sysctl_tcp_syncookies
> 		int	sysctl_tcp_tw_reuse
> 		int	tcp_memory_pressure
> 		int	time_status
> 		int	timer_stats_active
> 		int	x2apic_phys
> 		int	x86_cpu_to_node_map
> 		int*	console_printk
> 		int*	sysctl_tcp_mem
> 		int*	sysctl_tcp_rmem
> 		int*	sysctl_tcp_wmem
> 		int*	x86_cpu_to_node_map_early_ptr
> 		irq_cpustat_t	irq_stat
> 		long unsigned int	__kcrctab_ipv4_specific
> 		long unsigned int	__kcrctab_sysctl_tcp_low_latency
> 		long unsigned int	__kcrctab_tcp4_gro_complete
> 		long unsigned int	__kcrctab_tcp4_gro_receive
> 		long unsigned int	__kcrctab_tcp_hashinfo
> 		long unsigned int	__kcrctab_tcp_proc_register
> 		long unsigned int	__kcrctab_tcp_proc_unregister
> 		long unsigned int	__kcrctab_tcp_prot
> 		long unsigned int	__kcrctab_tcp_twsk_unique
> 		long unsigned int	__kcrctab_tcp_v4_conn_request
> 		long unsigned int	__kcrctab_tcp_v4_connect
> 		long unsigned int	__kcrctab_tcp_v4_destroy_sock
> 		long unsigned int	__kcrctab_tcp_v4_do_rcv
> 		long unsigned int	__kcrctab_tcp_v4_md5_do_add
> 		long unsigned int	__kcrctab_tcp_v4_md5_do_del
> 		long unsigned int	__kcrctab_tcp_v4_md5_hash_skb
> 		long unsigned int	__kcrctab_tcp_v4_md5_lookup
> 		long unsigned int	__kcrctab_tcp_v4_remember_stamp
> 		long unsigned int	__kcrctab_tcp_v4_send_check
> 		long unsigned int	__kcrctab_tcp_v4_syn_recv_sock
> 		long unsigned int	jiffies
> 		long unsigned int	kernel_stack
> 		long unsigned int	mmap_min_addr
> 		long unsigned int	mmu_cr4_features
> 		long unsigned int*	__per_cpu_offset
> 		long unsigned int*	cpu_bit_bitmap
> 		long unsigned int*	sysctl_local_reserved_ports
> 		nodemask_t*	node_states
> 		pg_data_t**	node_data
> 		physid_mask_t	phys_cpu_present_map
> 		pteval_t	__supported_pte_mask
> 		spinlock_t	dcache_lock
> 		struct address_space	swapper_space
> 		struct apic*	apic
> 		struct cache_sizes*	malloc_sizes
> 		struct cpuinfo_x86	boot_cpu_data
> 		struct cpuinfo_x86	cpu_info
> 		struct cpumask*	cpu_online_mask
> 		struct cpumask*	cpu_possible_mask
> 		struct cpumask*	cpu_present_mask
> 		struct device	x86_dma_fallback_dev
> 		struct dma_map_ops*	dma_ops
> 		struct dqstats	dqstats
> 		struct icmp_err*	icmp_err_convert
> 		struct inet_connection_sock_af_ops	ipv4_specific
> 		struct inet_hashinfo	tcp_hashinfo
> 		struct inet_timewait_death_row	tcp_death_row
> 		struct kernel_symbol	__ksymtab_ipv4_specific
> 		struct kernel_symbol	__ksymtab_sysctl_tcp_low_latency
> 		struct kernel_symbol	__ksymtab_tcp4_gro_complete
> 		struct kernel_symbol	__ksymtab_tcp4_gro_receive
> 		struct kernel_symbol	__ksymtab_tcp_hashinfo
> 		struct kernel_symbol	__ksymtab_tcp_proc_register
> 		struct kernel_symbol	__ksymtab_tcp_proc_unregister
> 		struct kernel_symbol	__ksymtab_tcp_prot
> 		struct kernel_symbol	__ksymtab_tcp_twsk_unique
> 		struct kernel_symbol	__ksymtab_tcp_v4_conn_request
> 		struct kernel_symbol	__ksymtab_tcp_v4_connect
> 		struct kernel_symbol	__ksymtab_tcp_v4_destroy_sock
> 		struct kernel_symbol	__ksymtab_tcp_v4_do_rcv
> 		struct kernel_symbol	__ksymtab_tcp_v4_md5_do_add
> 		struct kernel_symbol	__ksymtab_tcp_v4_md5_do_del
> 		struct kernel_symbol	__ksymtab_tcp_v4_md5_hash_skb
> 		struct kernel_symbol	__ksymtab_tcp_v4_md5_lookup
> 		struct kernel_symbol	__ksymtab_tcp_v4_remember_stamp
> 		struct kernel_symbol	__ksymtab_tcp_v4_send_check
> 		struct kernel_symbol	__ksymtab_tcp_v4_syn_recv_sock
> 		struct list_head*	nf_hooks
> 		struct mem_section**	mem_section
> 		struct memnode	memnode
> 		struct neigh_table	nd_tbl
> 		struct nf_afinfo**	nf_afinfo
> 		struct percpu_counter	tcp_orphan_count
> 		struct percpu_counter	tcp_sockets_allocated
> 		struct pernet_operations	tcp4_net_ops
> 		struct pernet_operations	tcp_sk_ops
> 		struct pglist_data**	node_data
> 		struct pid*	cad_pid
> 		struct pid_namespace	init_pid_ns
> 		struct proto	tcp_prot
> 		struct pt_regs*	irq_regs
> 		struct pv_apic_ops	pv_apic_ops
> 		struct pv_cpu_ops	pv_cpu_ops
> 		struct pv_info	pv_info
> 		struct pv_irq_ops	pv_irq_ops
> 		struct pv_mmu_ops	pv_mmu_ops
> 		struct pv_time_ops	pv_time_ops
> 		struct request_sock_ops	tcp_request_sock_ops
> 		struct resource	ioport_resource
> 		struct rps_sock_flow_table*	rps_sock_flow_table
> 		struct sk_buff*	skb
> 		struct smp_ops	smp_ops
> 		struct sock*	sk
> 		struct task_struct*	current_task
> 		struct tcp_congestion_ops	tcp_init_congestion_ops
> 		struct tcp_request_sock_ops	tcp_request_sock_ipv4_ops
> 		struct tcp_seq_afinfo	tcp4_seq_afinfo
> 		struct tcp_sock_af_ops	tcp_sock_ipv4_specific
> 		struct timewait_sock_ops	tcp_timewait_sock_ops
> 		struct tracepoint	__tracepoint_irq_handler_entry
> 		struct tracepoint	__tracepoint_irq_handler_exit
> 		struct tracepoint	__tracepoint_kfree
> 		struct tracepoint	__tracepoint_kmalloc
> 		struct tracepoint	__tracepoint_kmalloc_node
> 		struct tracepoint	__tracepoint_kmem_cache_alloc
> 		struct tracepoint	__tracepoint_kmem_cache_alloc_node
> 		struct tracepoint	__tracepoint_kmem_cache_free
> 		struct tracepoint	__tracepoint_mm_page_alloc
> 		struct tracepoint	__tracepoint_mm_page_alloc_extfrag
> 		struct tracepoint	__tracepoint_mm_page_alloc_zone_locked
> 		struct tracepoint	__tracepoint_mm_page_free_direct
> 		struct tracepoint	__tracepoint_mm_page_pcpu_drain
> 		struct tracepoint	__tracepoint_mm_pagevec_free
> 		struct tracepoint	__tracepoint_module_free
> 		struct tracepoint	__tracepoint_module_get
> 		struct tracepoint	__tracepoint_module_load
> 		struct tracepoint	__tracepoint_module_put
> 		struct tracepoint	__tracepoint_module_request
> 		struct tracepoint	__tracepoint_softirq_entry
> 		struct tracepoint	__tracepoint_softirq_exit
> 		struct tracepoint	__tracepoint_softirq_raise
> 		struct vm_event_state	vm_event_states
> 		struct x86_init_ops	x86_init
> 		struct x86_platform_ops	x86_platform
> 		u16	x86_bios_cpu_apicid
> 		u32	inet_ehash_secret
> 		union irq_stack_union	irq_stack_union
> 		unsigned int	apic_verbosity
> 		unsigned int	sysctl_timer_migration
> 
> - Arnaldo
> --
> 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
2nd Dept. Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

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

* Re: [PATCH -tip  6/7] perf probe: Show accessible global variables
  2010-10-22  2:25     ` Masami Hiramatsu
@ 2010-10-22  5:31       ` Masami Hiramatsu
  0 siblings, 0 replies; 18+ messages in thread
From: Masami Hiramatsu @ 2010-10-22  5:31 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Ingo Molnar, Steven Rostedt, Srikar Dronamraju, linux-kernel,
	2nddept-manager, Peter Zijlstra, Paul Mackerras,
	Frederic Weisbecker

(2010/10/22 11:25), Masami Hiramatsu wrote:
> (2010/10/22 5:50), Arnaldo Carvalho de Melo wrote:
>> Em Thu, Oct 21, 2010 at 07:13:35PM +0900, Masami Hiramatsu escreveu:
>>> Add --externs for allowing --vars to show accessible
>>> global(externally defined) variables from a given probe
>>> point too.
>>> This will give you a hint which globals can be accessible
>>> from the probe point.
>>
>> Cool, but perhaps we need to filter out some of the globals? Things
>> like:
> 
> Hmm, yeah. So is that enough to filter out symbols which start with
> __k???tab_ and __crc_ ?
> 
> 
>>
>>                 long unsigned int       __kcrctab_tcp_hashinfo
>>                 long unsigned int       __kcrctab_tcp_proc_register
>>                 long unsigned int       __kcrctab_tcp_proc_unregister
>>                 long unsigned int       __kcrctab_tcp_prot

BTW, with my kernel (yesterday -tip/x86-64/gcc-4.4.4-10),
perf probe doesn't find these __k???tab_ symbols in
dwarf. (but those are still in /proc/kallsyms)
Maybe, something has been changed or it depends on some
config/environment.

Thank you,


-- 
Masami HIRAMATSU
2nd Dept. Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

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

* [tip:perf/urgent] perf probe: Fix type searching
  2010-10-21 10:13 ` [PATCH -tip 1/7] [BUGFIX] perf probe: Fix type searching Masami Hiramatsu
@ 2010-10-23 19:40   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 18+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-10-23 19:40 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra,
	masami.hiramatsu.pt, tglx, mingo

Commit-ID:  4046b8bb5ffae9ee916e504cdadee804f10e0c56
Gitweb:     http://git.kernel.org/tip/4046b8bb5ffae9ee916e504cdadee804f10e0c56
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 21 Oct 2010 19:13:02 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 21 Oct 2010 15:57:08 -0200

perf probe: Fix type searching

Fix to get the actual type die of variables by using dwarf_attr_integrate()
which gets attribute from die even if the type die is connected by
DW_AT_abstract_origin.

Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
LKML-Reference: <20101021101302.3542.38549.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-finder.c |   25 +++++++++++++++++--------
 1 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 32b81f7..a2d1f79 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -160,26 +160,35 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
 	return name ? (strcmp(tname, name) == 0) : false;
 }
 
+/* Get type die */
+static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+{
+	Dwarf_Attribute attr;
+
+	if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
+	    dwarf_formref_die(&attr, die_mem))
+		return die_mem;
+	else
+		return NULL;
+}
+
 /* 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;
+		vr_die = die_get_type(vr_die, die_mem);
+		if (!vr_die)
+			break;
+		tag = dwarf_tag(vr_die);
 	} 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 vr_die;
 }
 
 static bool die_is_signed_type(Dwarf_Die *tp_die)

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

* [tip:perf/urgent] perf probe: Fix local variable searching loop
  2010-10-21 10:13 ` [PATCH -tip 2/7] [BUGFIX] perf probe: Fix local variable searching loop Masami Hiramatsu
@ 2010-10-23 19:40   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 18+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-10-23 19:40 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra,
	masami.hiramatsu.pt, tglx, mingo

Commit-ID:  378eeaad3e1cfea7f6614018fb335de93df2ba1f
Gitweb:     http://git.kernel.org/tip/378eeaad3e1cfea7f6614018fb335de93df2ba1f
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 21 Oct 2010 19:13:09 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 21 Oct 2010 15:58:05 -0200

perf probe: Fix local variable searching loop

Fix to check the die's address and search into the die only if it has given
address.

This will avoid finding wrong variables in wrong basic block.

Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
LKML-Reference: <20101021101309.3542.46434.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-finder.c |   26 ++++++++++++++++++--------
 1 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index a2d1f79..abcaec5 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -329,25 +329,35 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
 	return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
 }
 
+struct __find_variable_param {
+	const char *name;
+	Dwarf_Addr addr;
+};
+
 static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
 {
-	const char *name = data;
+	struct __find_variable_param *fvp = data;
 	int tag;
 
 	tag = dwarf_tag(die_mem);
 	if ((tag == DW_TAG_formal_parameter ||
 	     tag == DW_TAG_variable) &&
-	    die_compare_name(die_mem, name))
+	    die_compare_name(die_mem, fvp->name))
 		return DIE_FIND_CB_FOUND;
 
-	return DIE_FIND_CB_CONTINUE;
+	if (dwarf_haspc(die_mem, fvp->addr))
+		return DIE_FIND_CB_CONTINUE;
+	else
+		return DIE_FIND_CB_SIBLING;
 }
 
-/* Find a variable called 'name' */
-static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
-				    Dwarf_Die *die_mem)
+/* Find a variable called 'name' at given address */
+static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
+				       Dwarf_Addr addr, Dwarf_Die *die_mem)
 {
-	return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
+	struct __find_variable_param fvp = { .name = name, .addr = addr};
+
+	return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
 			      die_mem);
 }
 
@@ -731,7 +741,7 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
 	pr_debug("Searching '%s' variable in context.\n",
 		 pf->pvar->var);
 	/* Search child die for local variables and parameters. */
-	if (die_find_variable(sp_die, pf->pvar->var, &vr_die))
+	if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die))
 		ret = convert_variable(&vr_die, pf);
 	else {
 		/* Search upper class */

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

* [tip:perf/urgent] perf probe: Support global variables
  2010-10-21 10:13 ` [PATCH -tip 3/7] perf probe: Support global variables Masami Hiramatsu
@ 2010-10-23 19:40   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 18+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-10-23 19:40 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra,
	masami.hiramatsu.pt, tglx, mingo

Commit-ID:  632941c4f8fbd5b90dcb1672cd0422dfd7332bc9
Gitweb:     http://git.kernel.org/tip/632941c4f8fbd5b90dcb1672cd0422dfd7332bc9
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 21 Oct 2010 19:13:16 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 21 Oct 2010 15:58:27 -0200

perf probe: Support global variables

Allow users to set external defined global variables as event arguments (e.g.
jiffies).

Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
LKML-Reference: <20101021101316.3542.1999.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-finder.c |   25 +++++++++++++++++--------
 1 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index abcaec5..c6fe80e 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -406,6 +406,9 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
 	struct probe_trace_arg *tvar = pf->tvar;
 	int ret;
 
+	if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
+		goto static_var;
+
 	/* TODO: handle more than 1 exprs */
 	if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
 	    dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
@@ -417,6 +420,7 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
 	}
 
 	if (op->atom == DW_OP_addr) {
+static_var:
 		/* Static variables on memory (not stack), make @varname */
 		ret = strlen(dwarf_diename(vr_die));
 		tvar->value = zalloc(ret + 2);
@@ -746,17 +750,22 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
 	else {
 		/* Search upper class */
 		nscopes = dwarf_getscopes_die(sp_die, &scopes);
-		if (nscopes > 0) {
-			ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var,
-						0, NULL, 0, 0, &vr_die);
-			if (ret >= 0)
+		while (nscopes-- > 1) {
+			pr_debug("Searching variables in %s\n",
+				 dwarf_diename(&scopes[nscopes]));
+			/* We should check this scope, so give dummy address */
+			if (die_find_variable_at(&scopes[nscopes],
+						 pf->pvar->var, 0,
+						 &vr_die)) {
 				ret = convert_variable(&vr_die, pf);
-			else
-				ret = -ENOENT;
+				goto found;
+			}
+		}
+		if (scopes)
 			free(scopes);
-		} else
-			ret = -ENOENT;
+		ret = -ENOENT;
 	}
+found:
 	if (ret < 0)
 		pr_warning("Failed to find '%s' in this function.\n",
 			   pf->pvar->var);

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

* [tip:perf/urgent] perf probe: Show accessible local variables
  2010-10-21 10:13 ` [PATCH -tip 4/7] perf probe: Show accessible local variables Masami Hiramatsu
@ 2010-10-23 19:41   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 18+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-10-23 19:41 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra,
	masami.hiramatsu.pt, fweisbec, tglx, mingo

Commit-ID:  cf6eb489e5c04c8f8d5fd7bf90b8346c987688bc
Gitweb:     http://git.kernel.org/tip/cf6eb489e5c04c8f8d5fd7bf90b8346c987688bc
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 21 Oct 2010 19:13:23 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 21 Oct 2010 15:59:06 -0200

perf probe: Show accessible local variables

Add -V (--vars) option for listing accessible local variables at given probe
point. This will help finding which local variables are available for event
arguments.

e.g.)
 # perf probe -V call_timer_fn:23
 Available variables at call_timer_fn:23
         @<run_timer_softirq+345>
                 function_type*  fn
                 int     preempt_count
                 long unsigned int       data
                 struct list_head        work_list
                 struct list_head*       head
                 struct timer_list*      timer
                 struct tvec_base*       base

Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20101021101323.3542.40282.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/Documentation/perf-probe.txt |    7 +
 tools/perf/builtin-probe.c              |   61 ++++-
 tools/perf/util/probe-event.c           |   72 ++++++
 tools/perf/util/probe-event.h           |    8 +
 tools/perf/util/probe-finder.c          |  412 ++++++++++++++++++++++++-------
 tools/perf/util/probe-finder.h          |   25 ++-
 6 files changed, 480 insertions(+), 105 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 27d52da..72f5d9e 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -17,6 +17,8 @@ or
 'perf probe' --list
 or
 'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
+or
+'perf probe' --vars='PROBEPOINT'
 
 DESCRIPTION
 -----------
@@ -57,6 +59,11 @@ OPTIONS
 	Show source code lines which can be probed. This needs an argument
 	which specifies a range of the source code. (see LINE SYNTAX for detail)
 
+-V::
+--vars=::
+	Show available local variables at given probe point. The argument
+	syntax is same as PROBE SYNTAX, but NO ARGs.
+
 -f::
 --force::
 	Forcibly add events with existing name.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 199d5e1..91bb6cf 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -50,6 +50,8 @@ static struct {
 	bool list_events;
 	bool force_add;
 	bool show_lines;
+	bool show_vars;
+	bool mod_events;
 	int nevents;
 	struct perf_probe_event events[MAX_PROBES];
 	struct strlist *dellist;
@@ -57,7 +59,6 @@ static struct {
 	int max_probe_points;
 } params;
 
-
 /* Parse an event definition. Note that any error must die. */
 static int parse_probe_event(const char *str)
 {
@@ -92,6 +93,7 @@ static int parse_probe_event_argv(int argc, const char **argv)
 	len = 0;
 	for (i = 0; i < argc; i++)
 		len += sprintf(&buf[len], "%s ", argv[i]);
+	params.mod_events = true;
 	ret = parse_probe_event(buf);
 	free(buf);
 	return ret;
@@ -100,9 +102,10 @@ static int parse_probe_event_argv(int argc, const char **argv)
 static int opt_add_probe_event(const struct option *opt __used,
 			      const char *str, int unset __used)
 {
-	if (str)
+	if (str) {
+		params.mod_events = true;
 		return parse_probe_event(str);
-	else
+	} else
 		return 0;
 }
 
@@ -110,6 +113,7 @@ static int opt_del_probe_event(const struct option *opt __used,
 			       const char *str, int unset __used)
 {
 	if (str) {
+		params.mod_events = true;
 		if (!params.dellist)
 			params.dellist = strlist__new(true, NULL);
 		strlist__add(params.dellist, str);
@@ -130,6 +134,25 @@ static int opt_show_lines(const struct option *opt __used,
 
 	return ret;
 }
+
+static int opt_show_vars(const struct option *opt __used,
+			 const char *str, int unset __used)
+{
+	struct perf_probe_event *pev = &params.events[params.nevents];
+	int ret;
+
+	if (!str)
+		return 0;
+
+	ret = parse_probe_event(str);
+	if (!ret && pev->nargs != 0) {
+		pr_err("  Error: '--vars' doesn't accept arguments.\n");
+		return -EINVAL;
+	}
+	params.show_vars = true;
+
+	return ret;
+}
 #endif
 
 static const char * const probe_usage[] = {
@@ -139,6 +162,7 @@ static const char * const probe_usage[] = {
 	"perf probe --list",
 #ifdef DWARF_SUPPORT
 	"perf probe --line 'LINEDESC'",
+	"perf probe --vars 'PROBEPOINT'",
 #endif
 	NULL
 };
@@ -180,6 +204,9 @@ static const struct option options[] = {
 	OPT_CALLBACK('L', "line", NULL,
 		     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
 		     "Show source code lines.", opt_show_lines),
+	OPT_CALLBACK('V', "vars", NULL,
+		     "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
+		     "Show accessible variables on PROBEDEF", opt_show_vars),
 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 		   "file", "vmlinux pathname"),
 	OPT_STRING('s', "source", &symbol_conf.source_prefix,
@@ -217,7 +244,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		usage_with_options(probe_usage, options);
 
 	if (params.list_events) {
-		if (params.nevents != 0 || params.dellist) {
+		if (params.mod_events) {
 			pr_err("  Error: Don't use --list with --add/--del.\n");
 			usage_with_options(probe_usage, options);
 		}
@@ -225,6 +252,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			pr_err("  Error: Don't use --list with --line.\n");
 			usage_with_options(probe_usage, options);
 		}
+		if (params.show_vars) {
+			pr_err(" Error: Don't use --list with --vars.\n");
+			usage_with_options(probe_usage, options);
+		}
 		ret = show_perf_probe_events();
 		if (ret < 0)
 			pr_err("  Error: Failed to show event list. (%d)\n",
@@ -234,9 +265,13 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 
 #ifdef DWARF_SUPPORT
 	if (params.show_lines) {
-		if (params.nevents != 0 || params.dellist) {
-			pr_warning("  Error: Don't use --line with"
-				   " --add/--del.\n");
+		if (params.mod_events) {
+			pr_err("  Error: Don't use --line with"
+			       " --add/--del.\n");
+			usage_with_options(probe_usage, options);
+		}
+		if (params.show_vars) {
+			pr_err(" Error: Don't use --line with --vars.\n");
 			usage_with_options(probe_usage, options);
 		}
 
@@ -245,6 +280,18 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			pr_err("  Error: Failed to show lines. (%d)\n", ret);
 		return ret;
 	}
+	if (params.show_vars) {
+		if (params.mod_events) {
+			pr_err("  Error: Don't use --vars with"
+			       " --add/--del.\n");
+			usage_with_options(probe_usage, options);
+		}
+		ret = show_available_vars(params.events, params.nevents,
+					  params.max_probe_points);
+		if (ret < 0)
+			pr_err("  Error: Failed to show vars. (%d)\n", ret);
+		return ret;
+	}
 #endif
 
 	if (params.dellist) {
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fcc16e4..288ebe8 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -378,6 +378,72 @@ end:
 	return ret;
 }
 
+static int show_available_vars_at(int fd, struct perf_probe_event *pev,
+				  int max_vls)
+{
+	char *buf;
+	int ret, i;
+	struct str_node *node;
+	struct variable_list *vls = NULL, *vl;
+
+	buf = synthesize_perf_probe_point(&pev->point);
+	if (!buf)
+		return -EINVAL;
+	pr_debug("Searching variables at %s\n", buf);
+
+	ret = find_available_vars_at(fd, pev, &vls, max_vls);
+	if (ret > 0) {
+		/* Some variables were found */
+		fprintf(stdout, "Available variables at %s\n", buf);
+		for (i = 0; i < ret; i++) {
+			vl = &vls[i];
+			/*
+			 * A probe point might be converted to
+			 * several trace points.
+			 */
+			fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
+				vl->point.offset);
+			free(vl->point.symbol);
+			if (vl->vars) {
+				strlist__for_each(node, vl->vars)
+					fprintf(stdout, "\t\t%s\n", node->s);
+				strlist__delete(vl->vars);
+			} else
+				fprintf(stdout, "(No variables)\n");
+		}
+		free(vls);
+	} else
+		pr_err("Failed to find variables at %s (%d)\n", buf, ret);
+
+	free(buf);
+	return ret;
+}
+
+/* Show available variables on given probe point */
+int show_available_vars(struct perf_probe_event *pevs, int npevs,
+			int max_vls)
+{
+	int i, fd, ret = 0;
+
+	ret = init_vmlinux();
+	if (ret < 0)
+		return ret;
+
+	fd = open_vmlinux();
+	if (fd < 0) {
+		pr_warning("Failed to open debuginfo file.\n");
+		return fd;
+	}
+
+	setup_pager();
+
+	for (i = 0; i < npevs && ret >= 0; i++)
+		ret = show_available_vars_at(fd, &pevs[i], max_vls);
+
+	close(fd);
+	return ret;
+}
+
 #else	/* !DWARF_SUPPORT */
 
 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
@@ -409,6 +475,12 @@ int show_line_range(struct line_range *lr __unused)
 	return -ENOSYS;
 }
 
+int show_available_vars(struct perf_probe_event *pevs __unused,
+			int npevs __unused, int max_probe_points __unused)
+{
+	pr_warning("Debuginfo-analysis is not supported.\n");
+	return -ENOSYS;
+}
 #endif
 
 int parse_line_range_desc(const char *arg, struct line_range *lr)
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5af3924..727a7fe 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -90,6 +90,12 @@ struct line_range {
 	struct list_head	line_list;	/* Visible lines */
 };
 
+/* List of variables */
+struct variable_list {
+	struct probe_trace_point	point;	/* Actual probepoint */
+	struct strlist			*vars;	/* Available variables */
+};
+
 /* Command string to events */
 extern int parse_perf_probe_command(const char *cmd,
 				    struct perf_probe_event *pev);
@@ -115,6 +121,8 @@ extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
 extern int del_perf_probe_events(struct strlist *dellist);
 extern int show_perf_probe_events(void);
 extern int show_line_range(struct line_range *lr);
+extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
+			       int max_probe_points);
 
 
 /* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c6fe80e..986027f 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -172,8 +172,8 @@ static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
 		return NULL;
 }
 
-/* Get type die, but skip qualifiers and typedef */
-static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+/* Get a type die, but skip qualifiers */
+static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
 {
 	int tag;
 
@@ -185,8 +185,17 @@ static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_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);
+		 tag == DW_TAG_shared_type);
+
+	return vr_die;
+}
+
+/* Get a type die, but skip qualifiers and typedef */
+static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+{
+	do {
+		vr_die = __die_get_real_type(vr_die, die_mem);
+	} while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
 
 	return vr_die;
 }
@@ -380,6 +389,60 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
 			      die_mem);
 }
 
+/* Get the name of given variable DIE */
+static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
+{
+	Dwarf_Die type;
+	int tag, ret, ret2;
+	const char *tmp = "";
+
+	if (__die_get_real_type(vr_die, &type) == NULL)
+		return -ENOENT;
+
+	tag = dwarf_tag(&type);
+	if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
+		tmp = "*";
+	else if (tag == DW_TAG_subroutine_type) {
+		/* Function pointer */
+		ret = snprintf(buf, len, "(function_type)");
+		return (ret >= len) ? -E2BIG : ret;
+	} else {
+		if (!dwarf_diename(&type))
+			return -ENOENT;
+		if (tag == DW_TAG_union_type)
+			tmp = "union ";
+		else if (tag == DW_TAG_structure_type)
+			tmp = "struct ";
+		/* Write a base name */
+		ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
+		return (ret >= len) ? -E2BIG : ret;
+	}
+	ret = die_get_typename(&type, buf, len);
+	if (ret > 0) {
+		ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
+		ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
+	}
+	return ret;
+}
+
+/* Get the name and type of given variable DIE, stored as "type\tname" */
+static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
+{
+	int ret, ret2;
+
+	ret = die_get_typename(vr_die, buf, len);
+	if (ret < 0) {
+		pr_debug("Failed to get type, make it unknown.\n");
+		ret = snprintf(buf, len, "(unknown_type)");
+	}
+	if (ret > 0) {
+		ret2 = snprintf(buf + ret, len - ret, "\t%s",
+				dwarf_diename(vr_die));
+		ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
+	}
+	return ret;
+}
+
 /*
  * Probe finder related functions
  */
@@ -393,8 +456,13 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
 	return ref;
 }
 
-/* Show a location */
-static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
+/*
+ * Convert a location into trace_arg.
+ * If tvar == NULL, this just checks variable can be converted.
+ */
+static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
+				     Dwarf_Op *fb_ops,
+				     struct probe_trace_arg *tvar)
 {
 	Dwarf_Attribute attr;
 	Dwarf_Op *op;
@@ -403,7 +471,6 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
 	Dwarf_Word offs = 0;
 	bool ref = false;
 	const char *regs;
-	struct probe_trace_arg *tvar = pf->tvar;
 	int ret;
 
 	if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
@@ -411,16 +478,16 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
 
 	/* TODO: handle more than 1 exprs */
 	if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
-	    dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
+	    dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||
 	    nops == 0) {
 		/* TODO: Support const_value */
-		pr_err("Failed to find the location of %s at this address.\n"
-		       " Perhaps, it has been optimized out.\n", pf->pvar->var);
 		return -ENOENT;
 	}
 
 	if (op->atom == DW_OP_addr) {
 static_var:
+		if (!tvar)
+			return 0;
 		/* Static variables on memory (not stack), make @varname */
 		ret = strlen(dwarf_diename(vr_die));
 		tvar->value = zalloc(ret + 2);
@@ -435,14 +502,11 @@ static_var:
 
 	/* If this is based on frame buffer, set the offset */
 	if (op->atom == DW_OP_fbreg) {
-		if (pf->fb_ops == NULL) {
-			pr_warning("The attribute of frame base is not "
-				   "supported.\n");
+		if (fb_ops == NULL)
 			return -ENOTSUP;
-		}
 		ref = true;
 		offs = op->number;
-		op = &pf->fb_ops[0];
+		op = &fb_ops[0];
 	}
 
 	if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
@@ -458,13 +522,18 @@ static_var:
 	} else if (op->atom == DW_OP_regx) {
 		regn = op->number;
 	} else {
-		pr_warning("DW_OP %x is not supported.\n", op->atom);
+		pr_debug("DW_OP %x is not supported.\n", op->atom);
 		return -ENOTSUP;
 	}
 
+	if (!tvar)
+		return 0;
+
 	regs = get_arch_regstr(regn);
 	if (!regs) {
-		pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn);
+		/* This should be a bug in DWARF or this tool */
+		pr_warning("Mapping for DWARF register number %u "
+			   "missing on this architecture.", regn);
 		return -ERANGE;
 	}
 
@@ -689,8 +758,14 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
 	pr_debug("Converting variable %s into trace event.\n",
 		 dwarf_diename(vr_die));
 
-	ret = convert_variable_location(vr_die, pf);
-	if (ret == 0 && pf->pvar->field) {
+	ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
+					pf->tvar);
+	if (ret == -ENOENT)
+		pr_err("Failed to find the location of %s at this address.\n"
+		       " Perhaps, it has been optimized out.\n", pf->pvar->var);
+	else if (ret == -ENOTSUP)
+		pr_err("Sorry, we don't support this variable location yet.\n");
+	else if (pf->pvar->field) {
 		ret = convert_variable_fields(vr_die, pf->pvar->var,
 					      pf->pvar->field, &pf->tvar->ref,
 					      &die_mem);
@@ -772,34 +847,12 @@ found:
 	return ret;
 }
 
-/* Show a probe point to output buffer */
-static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
+/* Convert subprogram DIE to trace point */
+static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
+				  bool retprobe, struct probe_trace_point *tp)
 {
-	struct probe_trace_event *tev;
 	Dwarf_Addr eaddr;
-	Dwarf_Die die_mem;
 	const char *name;
-	int ret, i;
-	Dwarf_Attribute fb_attr;
-	size_t nops;
-
-	if (pf->ntevs == pf->max_tevs) {
-		pr_warning("Too many( > %d) probe point found.\n",
-			   pf->max_tevs);
-		return -ERANGE;
-	}
-	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,
-						 pf->addr, &die_mem);
-		if (!sp_die) {
-			pr_warning("Failed to find probe point in any "
-				   "functions.\n");
-			return -ENOENT;
-		}
-	}
 
 	/* Copy the name of probe point */
 	name = dwarf_diename(sp_die);
@@ -809,26 +862,45 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 				   dwarf_diename(sp_die));
 			return -ENOENT;
 		}
-		tev->point.symbol = strdup(name);
-		if (tev->point.symbol == NULL)
+		tp->symbol = strdup(name);
+		if (tp->symbol == NULL)
 			return -ENOMEM;
-		tev->point.offset = (unsigned long)(pf->addr - eaddr);
+		tp->offset = (unsigned long)(paddr - eaddr);
 	} else
 		/* This function has no name. */
-		tev->point.offset = (unsigned long)pf->addr;
+		tp->offset = (unsigned long)paddr;
 
 	/* Return probe must be on the head of a subprogram */
-	if (pf->pev->point.retprobe) {
-		if (tev->point.offset != 0) {
+	if (retprobe) {
+		if (eaddr != paddr) {
 			pr_warning("Return probe must be on the head of"
 				   " a real function\n");
 			return -EINVAL;
 		}
-		tev->point.retprobe = true;
+		tp->retprobe = true;
 	}
 
-	pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
-		 tev->point.offset);
+	return 0;
+}
+
+/* Call probe_finder callback with real subprogram DIE */
+static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+	Dwarf_Die die_mem;
+	Dwarf_Attribute fb_attr;
+	size_t nops;
+	int ret;
+
+	/* 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,
+						  pf->addr, &die_mem);
+		if (!sp_die) {
+			pr_warning("Failed to find probe point in any "
+				   "functions.\n");
+			return -ENOENT;
+		}
+	}
 
 	/* Get the frame base attribute/ops */
 	dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
@@ -848,22 +920,13 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 #endif
 	}
 
-	/* Find each argument */
-	tev->nargs = pf->pev->nargs;
-	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
-	if (tev->args == NULL)
-		return -ENOMEM;
-	for (i = 0; i < pf->pev->nargs; i++) {
-		pf->pvar = &pf->pev->args[i];
-		pf->tvar = &tev->args[i];
-		ret = find_variable(sp_die, pf);
-		if (ret != 0)
-			return ret;
-	}
+	/* Call finder's callback handler */
+	ret = pf->callback(sp_die, pf);
 
 	/* *pf->fb_ops will be cached in libdw. Don't free it. */
 	pf->fb_ops = NULL;
-	return 0;
+
+	return ret;
 }
 
 /* Find probe point from its line number */
@@ -899,7 +962,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
 			 (int)i, lineno, (uintmax_t)addr);
 		pf->addr = addr;
 
-		ret = convert_probe_point(NULL, pf);
+		ret = call_probe_finder(NULL, pf);
 		/* Continuing, because target line might be inlined. */
 	}
 	return ret;
@@ -1012,7 +1075,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 			 (int)i, lineno, (unsigned long long)addr);
 		pf->addr = addr;
 
-		ret = convert_probe_point(sp_die, pf);
+		ret = call_probe_finder(sp_die, pf);
 		/* Continuing, because target line might be inlined. */
 	}
 	/* TODO: deallocate lines, but how? */
@@ -1047,7 +1110,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);
 
-		param->retval = convert_probe_point(in_die, pf);
+		param->retval = call_probe_finder(in_die, pf);
 		if (param->retval < 0)
 			return DWARF_CB_ABORT;
 	}
@@ -1085,7 +1148,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
 			}
 			pf->addr += pp->offset;
 			/* TODO: Check the address in this function */
-			param->retval = convert_probe_point(sp_die, pf);
+			param->retval = call_probe_finder(sp_die, pf);
 		}
 	} else {
 		struct dwarf_callback_param _param = {.data = (void *)pf,
@@ -1107,70 +1170,229 @@ static int find_probe_point_by_func(struct probe_finder *pf)
 	return _param.retval;
 }
 
-/* Find probe_trace_events specified by perf_probe_event from debuginfo */
-int find_probe_trace_events(int fd, struct perf_probe_event *pev,
-			     struct probe_trace_event **tevs, int max_tevs)
+/* Find probe points from debuginfo */
+static int find_probes(int fd, struct probe_finder *pf)
 {
-	struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};
-	struct perf_probe_point *pp = &pev->point;
+	struct perf_probe_point *pp = &pf->pev->point;
 	Dwarf_Off off, noff;
 	size_t cuhl;
 	Dwarf_Die *diep;
 	Dwarf *dbg;
 	int ret = 0;
 
-	pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
-	if (pf.tevs == NULL)
-		return -ENOMEM;
-	*tevs = pf.tevs;
-	pf.ntevs = 0;
-
 	dbg = dwarf_begin(fd, DWARF_C_READ);
 	if (!dbg) {
 		pr_warning("No dwarf info found in the vmlinux - "
 			"please rebuild with CONFIG_DEBUG_INFO=y.\n");
-		free(pf.tevs);
-		*tevs = NULL;
 		return -EBADF;
 	}
 
 #if _ELFUTILS_PREREQ(0, 142)
 	/* Get the call frame information from this dwarf */
-	pf.cfi = dwarf_getcfi(dbg);
+	pf->cfi = dwarf_getcfi(dbg);
 #endif
 
 	off = 0;
-	line_list__init(&pf.lcache);
+	line_list__init(&pf->lcache);
 	/* Loop on CUs (Compilation Unit) */
 	while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&
 	       ret >= 0) {
 		/* Get the DIE(Debugging Information Entry) of this CU */
-		diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
+		diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
 		if (!diep)
 			continue;
 
 		/* Check if target file is included. */
 		if (pp->file)
-			pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
+			pf->fname = cu_find_realpath(&pf->cu_die, pp->file);
 		else
-			pf.fname = NULL;
+			pf->fname = NULL;
 
-		if (!pp->file || pf.fname) {
+		if (!pp->file || pf->fname) {
 			if (pp->function)
-				ret = find_probe_point_by_func(&pf);
+				ret = find_probe_point_by_func(pf);
 			else if (pp->lazy_line)
-				ret = find_probe_point_lazy(NULL, &pf);
+				ret = find_probe_point_lazy(NULL, pf);
 			else {
-				pf.lno = pp->line;
-				ret = find_probe_point_by_line(&pf);
+				pf->lno = pp->line;
+				ret = find_probe_point_by_line(pf);
 			}
 		}
 		off = noff;
 	}
-	line_list__free(&pf.lcache);
+	line_list__free(&pf->lcache);
 	dwarf_end(dbg);
 
-	return (ret < 0) ? ret : pf.ntevs;
+	return ret;
+}
+
+/* Add a found probe point into trace event list */
+static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+	struct trace_event_finder *tf =
+			container_of(pf, struct trace_event_finder, pf);
+	struct probe_trace_event *tev;
+	int ret, i;
+
+	/* Check number of tevs */
+	if (tf->ntevs == tf->max_tevs) {
+		pr_warning("Too many( > %d) probe point found.\n",
+			   tf->max_tevs);
+		return -ERANGE;
+	}
+	tev = &tf->tevs[tf->ntevs++];
+
+	ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
+				     &tev->point);
+	if (ret < 0)
+		return ret;
+
+	pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
+		 tev->point.offset);
+
+	/* Find each argument */
+	tev->nargs = pf->pev->nargs;
+	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
+	if (tev->args == NULL)
+		return -ENOMEM;
+	for (i = 0; i < pf->pev->nargs; i++) {
+		pf->pvar = &pf->pev->args[i];
+		pf->tvar = &tev->args[i];
+		ret = find_variable(sp_die, pf);
+		if (ret != 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/* Find probe_trace_events specified by perf_probe_event from debuginfo */
+int find_probe_trace_events(int fd, struct perf_probe_event *pev,
+			    struct probe_trace_event **tevs, int max_tevs)
+{
+	struct trace_event_finder tf = {
+			.pf = {.pev = pev, .callback = add_probe_trace_event},
+			.max_tevs = max_tevs};
+	int ret;
+
+	/* Allocate result tevs array */
+	*tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
+	if (*tevs == NULL)
+		return -ENOMEM;
+
+	tf.tevs = *tevs;
+	tf.ntevs = 0;
+
+	ret = find_probes(fd, &tf.pf);
+	if (ret < 0) {
+		free(*tevs);
+		*tevs = NULL;
+		return ret;
+	}
+
+	return (ret < 0) ? ret : tf.ntevs;
+}
+
+#define MAX_VAR_LEN 64
+
+/* Collect available variables in this scope */
+static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
+{
+	struct available_var_finder *af = data;
+	struct variable_list *vl;
+	char buf[MAX_VAR_LEN];
+	int tag, ret;
+
+	vl = &af->vls[af->nvls - 1];
+
+	tag = dwarf_tag(die_mem);
+	if (tag == DW_TAG_formal_parameter ||
+	    tag == DW_TAG_variable) {
+		ret = convert_variable_location(die_mem, af->pf.addr,
+						af->pf.fb_ops, NULL);
+		if (ret == 0) {
+			ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
+			if (ret > 0)
+				strlist__add(vl->vars, buf);
+		}
+	}
+
+	if (dwarf_haspc(die_mem, af->pf.addr))
+		return DIE_FIND_CB_CONTINUE;
+	else
+		return DIE_FIND_CB_SIBLING;
+}
+
+/* Add a found vars into available variables list */
+static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+	struct available_var_finder *af =
+			container_of(pf, struct available_var_finder, pf);
+	struct variable_list *vl;
+	Dwarf_Die die_mem;
+	int ret;
+
+	/* Check number of tevs */
+	if (af->nvls == af->max_vls) {
+		pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
+		return -ERANGE;
+	}
+	vl = &af->vls[af->nvls++];
+
+	ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
+				     &vl->point);
+	if (ret < 0)
+		return ret;
+
+	pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,
+		 vl->point.offset);
+
+	/* Find local variables */
+	vl->vars = strlist__new(true, NULL);
+	if (vl->vars == NULL)
+		return -ENOMEM;
+	die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
+
+	if (strlist__empty(vl->vars)) {
+		strlist__delete(vl->vars);
+		vl->vars = NULL;
+	}
+
+	return ret;
+}
+
+/* Find available variables at given probe point */
+int find_available_vars_at(int fd, struct perf_probe_event *pev,
+			   struct variable_list **vls, int max_vls)
+{
+	struct available_var_finder af = {
+			.pf = {.pev = pev, .callback = add_available_vars},
+			.max_vls = max_vls};
+	int ret;
+
+	/* Allocate result vls array */
+	*vls = zalloc(sizeof(struct variable_list) * max_vls);
+	if (*vls == NULL)
+		return -ENOMEM;
+
+	af.vls = *vls;
+	af.nvls = 0;
+
+	ret = find_probes(fd, &af.pf);
+	if (ret < 0) {
+		/* Free vlist for error */
+		while (af.nvls--) {
+			if (af.vls[af.nvls].point.symbol)
+				free(af.vls[af.nvls].point.symbol);
+			if (af.vls[af.nvls].vars)
+				strlist__delete(af.vls[af.nvls].vars);
+		}
+		free(af.vls);
+		*vls = NULL;
+		return ret;
+	}
+
+	return (ret < 0) ? ret : af.nvls;
 }
 
 /* Reverse search */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 4507d51..baffd25 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -25,17 +25,22 @@ extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
 extern int find_perf_probe_point(int fd, unsigned long addr,
 				 struct perf_probe_point *ppt);
 
+/* Find a line range */
 extern int find_line_range(int fd, struct line_range *lr);
 
+/* Find available variables */
+extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
+				  struct variable_list **vls, int max_points);
+
 #include <dwarf.h>
 #include <libdw.h>
 #include <version.h>
 
 struct probe_finder {
 	struct perf_probe_event	*pev;		/* Target probe event */
-	struct probe_trace_event *tevs;		/* Result trace events */
-	int			ntevs;		/* Number of trace events */
-	int			max_tevs;	/* Max number of trace events */
+
+	/* Callback when a probe point is found */
+	int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf);
 
 	/* For function searching */
 	int			lno;		/* Line number */
@@ -53,6 +58,20 @@ struct probe_finder {
 	struct probe_trace_arg	*tvar;		/* Current result variable */
 };
 
+struct trace_event_finder {
+	struct probe_finder	pf;
+	struct probe_trace_event *tevs;		/* Found trace events */
+	int			ntevs;		/* Number of trace events */
+	int			max_tevs;	/* Max number of trace events */
+};
+
+struct available_var_finder {
+	struct probe_finder	pf;
+	struct variable_list	*vls;		/* Found variable lists */
+	int			nvls;		/* Number of variable lists */
+	int			max_vls;	/* Max no. of variable lists */
+};
+
 struct line_finder {
 	struct line_range	*lr;		/* Target line range */
 

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

* [tip:perf/urgent] perf probe: Function style fix
  2010-10-21 10:13 ` [PATCH -tip 5/7] perf probe: Function style fix Masami Hiramatsu
@ 2010-10-23 19:41   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 18+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-10-23 19:41 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra,
	masami.hiramatsu.pt, fweisbec, tglx, mingo

Commit-ID:  c82ec0a2bd7725a2d2ac3065d8cde13e1f717d3c
Gitweb:     http://git.kernel.org/tip/c82ec0a2bd7725a2d2ac3065d8cde13e1f717d3c
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 21 Oct 2010 19:13:29 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 21 Oct 2010 16:00:42 -0200

perf probe: Function style fix

Just change the order of function arguments for ease of read; moving optional
bool flag to the last.

Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20101021101329.3542.51200.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-probe.c    |    4 ++--
 tools/perf/util/probe-event.c |    2 +-
 tools/perf/util/probe-event.h |    2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 91bb6cf..c777bec 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -305,8 +305,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 
 	if (params.nevents) {
 		ret = add_perf_probe_events(params.events, params.nevents,
-					    params.force_add,
-					    params.max_probe_points);
+					    params.max_probe_points,
+					    params.force_add);
 		if (ret < 0) {
 			pr_err("  Error: Failed to add events. (%d)\n", ret);
 			return ret;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 288ebe8..83192a5 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1668,7 +1668,7 @@ struct __event_package {
 };
 
 int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
-			  bool force_add, int max_tevs)
+			  int max_tevs, bool force_add)
 {
 	int i, j, ret;
 	struct __event_package *pkgs;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 727a7fe..83130f6 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -117,7 +117,7 @@ extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
 
 
 extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
-				 bool force_add, int max_probe_points);
+				 int max_probe_points, bool force_add);
 extern int del_perf_probe_events(struct strlist *dellist);
 extern int show_perf_probe_events(void);
 extern int show_line_range(struct line_range *lr);

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

* [tip:perf/urgent] perf probe: Show accessible global variables
  2010-10-21 10:13 ` [PATCH -tip 6/7] perf probe: Show accessible global variables Masami Hiramatsu
  2010-10-21 20:50   ` Arnaldo Carvalho de Melo
@ 2010-10-23 19:42   ` tip-bot for Masami Hiramatsu
  1 sibling, 0 replies; 18+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-10-23 19:42 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra,
	masami.hiramatsu.pt, fweisbec, tglx, mingo

Commit-ID:  fb8c5a56c7ddbc2b0d2ee7a8da60fe1355f75141
Gitweb:     http://git.kernel.org/tip/fb8c5a56c7ddbc2b0d2ee7a8da60fe1355f75141
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 21 Oct 2010 19:13:35 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 21 Oct 2010 16:06:42 -0200

perf probe: Show accessible global variables

Add --externs for allowing --vars to show accessible global (externally
defined) variables from a given probe point too.

This will give you a hint which globals can be accessible from the probe point.

Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20101021101335.3542.31003.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/Documentation/perf-probe.txt |    6 +++++-
 tools/perf/builtin-probe.c              |    8 ++++++--
 tools/perf/util/probe-event.c           |    8 ++++----
 tools/perf/util/probe-event.h           |    2 +-
 tools/perf/util/probe-finder.c          |   26 +++++++++++++++++++++-----
 tools/perf/util/probe-finder.h          |    5 ++++-
 6 files changed, 41 insertions(+), 14 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 72f5d9e..148c178 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -18,7 +18,7 @@ or
 or
 'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
 or
-'perf probe' --vars='PROBEPOINT'
+'perf probe' [--externs] --vars='PROBEPOINT'
 
 DESCRIPTION
 -----------
@@ -64,6 +64,10 @@ OPTIONS
 	Show available local variables at given probe point. The argument
 	syntax is same as PROBE SYNTAX, but NO ARGs.
 
+--externs::
+	(Only for --vars) Show external defined variables in addition to local
+	variables.
+
 -f::
 --force::
 	Forcibly add events with existing name.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index c777bec..bdf60cf 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -51,6 +51,7 @@ static struct {
 	bool force_add;
 	bool show_lines;
 	bool show_vars;
+	bool show_ext_vars;
 	bool mod_events;
 	int nevents;
 	struct perf_probe_event events[MAX_PROBES];
@@ -162,7 +163,7 @@ static const char * const probe_usage[] = {
 	"perf probe --list",
 #ifdef DWARF_SUPPORT
 	"perf probe --line 'LINEDESC'",
-	"perf probe --vars 'PROBEPOINT'",
+	"perf probe [--externs] --vars 'PROBEPOINT'",
 #endif
 	NULL
 };
@@ -207,6 +208,8 @@ static const struct option options[] = {
 	OPT_CALLBACK('V', "vars", NULL,
 		     "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
 		     "Show accessible variables on PROBEDEF", opt_show_vars),
+	OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
+		    "Show external variables too (with --vars only)"),
 	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 		   "file", "vmlinux pathname"),
 	OPT_STRING('s', "source", &symbol_conf.source_prefix,
@@ -287,7 +290,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			usage_with_options(probe_usage, options);
 		}
 		ret = show_available_vars(params.events, params.nevents,
-					  params.max_probe_points);
+					  params.max_probe_points,
+					  params.show_ext_vars);
 		if (ret < 0)
 			pr_err("  Error: Failed to show vars. (%d)\n", ret);
 		return ret;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 83192a5..82b0976 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -379,7 +379,7 @@ end:
 }
 
 static int show_available_vars_at(int fd, struct perf_probe_event *pev,
-				  int max_vls)
+				  int max_vls, bool externs)
 {
 	char *buf;
 	int ret, i;
@@ -391,7 +391,7 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
 		return -EINVAL;
 	pr_debug("Searching variables at %s\n", buf);
 
-	ret = find_available_vars_at(fd, pev, &vls, max_vls);
+	ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
 	if (ret > 0) {
 		/* Some variables were found */
 		fprintf(stdout, "Available variables at %s\n", buf);
@@ -421,7 +421,7 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
 
 /* Show available variables on given probe point */
 int show_available_vars(struct perf_probe_event *pevs, int npevs,
-			int max_vls)
+			int max_vls, bool externs)
 {
 	int i, fd, ret = 0;
 
@@ -438,7 +438,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
 	setup_pager();
 
 	for (i = 0; i < npevs && ret >= 0; i++)
-		ret = show_available_vars_at(fd, &pevs[i], max_vls);
+		ret = show_available_vars_at(fd, &pevs[i], max_vls, externs);
 
 	close(fd);
 	return ret;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 83130f6..c74b1fd 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -122,7 +122,7 @@ extern int del_perf_probe_events(struct strlist *dellist);
 extern int show_perf_probe_events(void);
 extern int show_line_range(struct line_range *lr);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
-			       int max_probe_points);
+			       int max_probe_points, bool externs);
 
 
 /* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 986027f..a274fd0 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -1312,12 +1312,13 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
 						af->pf.fb_ops, NULL);
 		if (ret == 0) {
 			ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
+			pr_debug2("Add new var: %s\n", buf);
 			if (ret > 0)
 				strlist__add(vl->vars, buf);
 		}
 	}
 
-	if (dwarf_haspc(die_mem, af->pf.addr))
+	if (af->child && dwarf_haspc(die_mem, af->pf.addr))
 		return DIE_FIND_CB_CONTINUE;
 	else
 		return DIE_FIND_CB_SIBLING;
@@ -1329,8 +1330,8 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
 	struct available_var_finder *af =
 			container_of(pf, struct available_var_finder, pf);
 	struct variable_list *vl;
-	Dwarf_Die die_mem;
-	int ret;
+	Dwarf_Die die_mem, *scopes = NULL;
+	int ret, nscopes;
 
 	/* Check number of tevs */
 	if (af->nvls == af->max_vls) {
@@ -1351,8 +1352,22 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
 	vl->vars = strlist__new(true, NULL);
 	if (vl->vars == NULL)
 		return -ENOMEM;
+	af->child = true;
 	die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
 
+	/* Find external variables */
+	if (!af->externs)
+		goto out;
+	/* Don't need to search child DIE for externs. */
+	af->child = false;
+	nscopes = dwarf_getscopes_die(sp_die, &scopes);
+	while (nscopes-- > 1)
+		die_find_child(&scopes[nscopes], collect_variables_cb,
+			       (void *)af, &die_mem);
+	if (scopes)
+		free(scopes);
+
+out:
 	if (strlist__empty(vl->vars)) {
 		strlist__delete(vl->vars);
 		vl->vars = NULL;
@@ -1363,11 +1378,12 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
 
 /* Find available variables at given probe point */
 int find_available_vars_at(int fd, struct perf_probe_event *pev,
-			   struct variable_list **vls, int max_vls)
+			   struct variable_list **vls, int max_vls,
+			   bool externs)
 {
 	struct available_var_finder af = {
 			.pf = {.pev = pev, .callback = add_available_vars},
-			.max_vls = max_vls};
+			.max_vls = max_vls, .externs = externs};
 	int ret;
 
 	/* Allocate result vls array */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index baffd25..516912a 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -30,7 +30,8 @@ extern int find_line_range(int fd, struct line_range *lr);
 
 /* Find available variables */
 extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
-				  struct variable_list **vls, int max_points);
+				  struct variable_list **vls, int max_points,
+				  bool externs);
 
 #include <dwarf.h>
 #include <libdw.h>
@@ -70,6 +71,8 @@ struct available_var_finder {
 	struct variable_list	*vls;		/* Found variable lists */
 	int			nvls;		/* Number of variable lists */
 	int			max_vls;	/* Max no. of variable lists */
+	bool			externs;	/* Find external vars too */
+	bool			child;		/* Search child scopes */
 };
 
 struct line_finder {

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

* [tip:perf/urgent] perf probe: Add basic module support
  2010-10-21 10:13 ` [PATCH -tip 7/7] perf probe: Add basic module support Masami Hiramatsu
@ 2010-10-23 19:42   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 18+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2010-10-23 19:42 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, paulus, hpa, mingo, a.p.zijlstra,
	masami.hiramatsu.pt, fweisbec, tglx, mingo

Commit-ID:  469b9b88488e89114bb3e9ac5ee7906b7b96123f
Gitweb:     http://git.kernel.org/tip/469b9b88488e89114bb3e9ac5ee7906b7b96123f
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 21 Oct 2010 19:13:41 +0900
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 21 Oct 2010 16:11:44 -0200

perf probe: Add basic module support

Add basic module probe support on perf probe. This introduces "--module
<MODNAME>" option to perf probe for putting probes and showing lines and
variables in the given module.

Currently, this supports only probing on running modules.  Supporting off-line
module probing is the next step.

e.g.)
[show lines]
 # ./perf probe --module drm -L drm_vblank_info
<drm_vblank_info:0>
      0  int drm_vblank_info(struct seq_file *m, void *data)
      1  {
                struct drm_info_node *node = (struct drm_info_node *) m->private
      3         struct drm_device *dev = node->minor->dev;
 ...
[show vars]
 # ./perf probe --module drm -V drm_vblank_info:3
Available variables at drm_vblank_info:3
        @<drm_vblank_info+20>
                (unknown_type)  data
                struct drm_info_node*   node
                struct seq_file*        m
[put a probe]
 # ./perf probe --module drm drm_vblank_info:3 node m
Add new event:
  probe:drm_vblank_info (on drm_vblank_info:3 with node m)

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

        perf record -e probe:drm_vblank_info -aR sleep 1
[list probes]
 # ./perf probe -l
probe:drm_vblank_info (on drm_vblank_info:3@drivers/gpu/drm/drm_info.c with ...

Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20101021101341.3542.71638.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/Documentation/perf-probe.txt |    9 ++-
 tools/perf/builtin-probe.c              |   11 ++-
 tools/perf/util/map.h                   |   10 ++
 tools/perf/util/probe-event.c           |  123 +++++++++++++++++----------
 tools/perf/util/probe-event.h           |   10 ++-
 tools/perf/util/probe-finder.c          |  142 +++++++++++++++++++++++++++----
 tools/perf/util/probe-finder.h          |    3 +-
 7 files changed, 239 insertions(+), 69 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 148c178..62de1b7 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -16,9 +16,9 @@ or
 or
 'perf probe' --list
 or
-'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
+'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
 or
-'perf probe' [--externs] --vars='PROBEPOINT'
+'perf probe' [options] --vars='PROBEPOINT'
 
 DESCRIPTION
 -----------
@@ -33,6 +33,11 @@ OPTIONS
 --vmlinux=PATH::
 	Specify vmlinux path which has debuginfo (Dwarf binary).
 
+-m::
+--module=MODNAME::
+	Specify module name in which perf-probe searches probe points
+	or lines.
+
 -s::
 --source=PATH::
 	Specify path to kernel source.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index bdf60cf..2e000c0 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -57,6 +57,7 @@ static struct {
 	struct perf_probe_event events[MAX_PROBES];
 	struct strlist *dellist;
 	struct line_range line_range;
+	const char *target_module;
 	int max_probe_points;
 } params;
 
@@ -162,8 +163,8 @@ static const char * const probe_usage[] = {
 	"perf probe [<options>] --del '[GROUP:]EVENT' ...",
 	"perf probe --list",
 #ifdef DWARF_SUPPORT
-	"perf probe --line 'LINEDESC'",
-	"perf probe [--externs] --vars 'PROBEPOINT'",
+	"perf probe [<options>] --line 'LINEDESC'",
+	"perf probe [<options>] --vars 'PROBEPOINT'",
 #endif
 	NULL
 };
@@ -214,6 +215,8 @@ static const struct option options[] = {
 		   "file", "vmlinux pathname"),
 	OPT_STRING('s', "source", &symbol_conf.source_prefix,
 		   "directory", "path to kernel source"),
+	OPT_STRING('m', "module", &params.target_module,
+		   "modname", "target module name"),
 #endif
 	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -278,7 +281,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 			usage_with_options(probe_usage, options);
 		}
 
-		ret = show_line_range(&params.line_range);
+		ret = show_line_range(&params.line_range, params.target_module);
 		if (ret < 0)
 			pr_err("  Error: Failed to show lines. (%d)\n", ret);
 		return ret;
@@ -291,6 +294,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 		}
 		ret = show_available_vars(params.events, params.nevents,
 					  params.max_probe_points,
+					  params.target_module,
 					  params.show_ext_vars);
 		if (ret < 0)
 			pr_err("  Error: Failed to show vars. (%d)\n", ret);
@@ -310,6 +314,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 	if (params.nevents) {
 		ret = add_perf_probe_events(params.events, params.nevents,
 					    params.max_probe_points,
+					    params.target_module,
 					    params.force_add);
 		if (ret < 0) {
 			pr_err("  Error: Failed to add events. (%d)\n", ret);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 7857579..b397c03 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -215,6 +215,16 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *self,
 	return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
 }
 
+static inline
+struct symbol *machine__find_kernel_function_by_name(struct machine *self,
+						     const char *name,
+						     struct map **mapp,
+						     symbol_filter_t filter)
+{
+	return map_groups__find_function_by_name(&self->kmaps, name, mapp,
+						 filter);
+}
+
 int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
 				   int verbose, FILE *fp);
 
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 82b0976..3b6a529 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -74,10 +74,9 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
 static struct machine machine;
 
-/* Initialize symbol maps and path of vmlinux */
+/* Initialize symbol maps and path of vmlinux/modules */
 static int init_vmlinux(void)
 {
-	struct dso *kernel;
 	int ret;
 
 	symbol_conf.sort_by_name = true;
@@ -91,33 +90,61 @@ static int init_vmlinux(void)
 		goto out;
 	}
 
-	ret = machine__init(&machine, "/", 0);
+	ret = machine__init(&machine, "", HOST_KERNEL_ID);
 	if (ret < 0)
 		goto out;
 
-	kernel = dso__new_kernel(symbol_conf.vmlinux_name);
-	if (kernel == NULL)
-		die("Failed to create kernel dso.");
-
-	ret = __machine__create_kernel_maps(&machine, kernel);
-	if (ret < 0)
-		pr_debug("Failed to create kernel maps.\n");
-
+	if (machine__create_kernel_maps(&machine) < 0) {
+		pr_debug("machine__create_kernel_maps ");
+		goto out;
+	}
 out:
 	if (ret < 0)
 		pr_warning("Failed to init vmlinux path.\n");
 	return ret;
 }
 
+static struct symbol *__find_kernel_function_by_name(const char *name,
+						     struct map **mapp)
+{
+	return machine__find_kernel_function_by_name(&machine, name, mapp,
+						     NULL);
+}
+
+const char *kernel_get_module_path(const char *module)
+{
+	struct dso *dso;
+
+	if (module) {
+		list_for_each_entry(dso, &machine.kernel_dsos, node) {
+			if (strncmp(dso->short_name + 1, module,
+				    dso->short_name_len - 2) == 0)
+				goto found;
+		}
+		pr_debug("Failed to find module %s.\n", module);
+		return NULL;
+	} else {
+		dso = machine.vmlinux_maps[MAP__FUNCTION]->dso;
+		if (dso__load_vmlinux_path(dso,
+			 machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
+			pr_debug("Failed to load kernel map.\n");
+			return NULL;
+		}
+	}
+found:
+	return dso->long_name;
+}
+
 #ifdef DWARF_SUPPORT
-static int open_vmlinux(void)
+static int open_vmlinux(const char *module)
 {
-	if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
-		pr_debug("Failed to load kernel map.\n");
-		return -EINVAL;
+	const char *path = kernel_get_module_path(module);
+	if (!path) {
+		pr_err("Failed to find path of %s module", module ?: "kernel");
+		return -ENOENT;
 	}
-	pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name);
-	return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
+	pr_debug("Try to open %s\n", path);
+	return open(path, O_RDONLY);
 }
 
 /*
@@ -125,20 +152,19 @@ static int open_vmlinux(void)
  * Currently only handles kprobes.
  */
 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-				       struct perf_probe_point *pp)
+					struct perf_probe_point *pp)
 {
 	struct symbol *sym;
-	int fd, ret = -ENOENT;
+	struct map *map;
+	u64 addr;
+	int ret = -ENOENT;
 
-	sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
-				       tp->symbol, NULL);
+	sym = __find_kernel_function_by_name(tp->symbol, &map);
 	if (sym) {
-		fd = open_vmlinux();
-		if (fd >= 0) {
-			ret = find_perf_probe_point(fd,
-						 sym->start + tp->offset, pp);
-			close(fd);
-		}
+		addr = map->unmap_ip(map, sym->start + tp->offset);
+		pr_debug("try to find %s+%ld@%llx\n", tp->symbol,
+			 tp->offset, addr);
+		ret = find_perf_probe_point((unsigned long)addr, pp);
 	}
 	if (ret <= 0) {
 		pr_debug("Failed to find corresponding probes from "
@@ -156,12 +182,12 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 /* Try to find perf_probe_event with debuginfo */
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 					   struct probe_trace_event **tevs,
-					   int max_tevs)
+					   int max_tevs, const char *module)
 {
 	bool need_dwarf = perf_probe_event_need_dwarf(pev);
 	int fd, ntevs;
 
-	fd = open_vmlinux();
+	fd = open_vmlinux(module);
 	if (fd < 0) {
 		if (need_dwarf) {
 			pr_warning("Failed to open debuginfo file.\n");
@@ -300,7 +326,7 @@ error:
  * Show line-range always requires debuginfo to find source file and
  * line number.
  */
-int show_line_range(struct line_range *lr)
+int show_line_range(struct line_range *lr, const char *module)
 {
 	int l = 1;
 	struct line_node *ln;
@@ -313,7 +339,7 @@ int show_line_range(struct line_range *lr)
 	if (ret < 0)
 		return ret;
 
-	fd = open_vmlinux();
+	fd = open_vmlinux(module);
 	if (fd < 0) {
 		pr_warning("Failed to open debuginfo file.\n");
 		return fd;
@@ -421,7 +447,7 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev,
 
 /* Show available variables on given probe point */
 int show_available_vars(struct perf_probe_event *pevs, int npevs,
-			int max_vls, bool externs)
+			int max_vls, const char *module, bool externs)
 {
 	int i, fd, ret = 0;
 
@@ -429,7 +455,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
 	if (ret < 0)
 		return ret;
 
-	fd = open_vmlinux();
+	fd = open_vmlinux(module);
 	if (fd < 0) {
 		pr_warning("Failed to open debuginfo file.\n");
 		return fd;
@@ -447,8 +473,15 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
 #else	/* !DWARF_SUPPORT */
 
 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-				       struct perf_probe_point *pp)
+					struct perf_probe_point *pp)
 {
+	struct symbol *sym;
+
+	sym = __find_kernel_function_by_name(tp->symbol, NULL);
+	if (!sym) {
+		pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
+		return -ENOENT;
+	}
 	pp->function = strdup(tp->symbol);
 	if (pp->function == NULL)
 		return -ENOMEM;
@@ -460,7 +493,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 				struct probe_trace_event **tevs __unused,
-				int max_tevs __unused)
+				int max_tevs __unused, const char *mod __unused)
 {
 	if (perf_probe_event_need_dwarf(pev)) {
 		pr_warning("Debuginfo-analysis is not supported.\n");
@@ -469,14 +502,15 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 	return 0;
 }
 
-int show_line_range(struct line_range *lr __unused)
+int show_line_range(struct line_range *lr __unused, const char *module __unused)
 {
 	pr_warning("Debuginfo-analysis is not supported.\n");
 	return -ENOSYS;
 }
 
 int show_available_vars(struct perf_probe_event *pevs __unused,
-			int npevs __unused, int max_probe_points __unused)
+			int npevs __unused, int max_vls __unused,
+			const char *module __unused, bool externs __unused)
 {
 	pr_warning("Debuginfo-analysis is not supported.\n");
 	return -ENOSYS;
@@ -1159,7 +1193,7 @@ error:
 }
 
 static int convert_to_perf_probe_event(struct probe_trace_event *tev,
-				struct perf_probe_event *pev)
+				       struct perf_probe_event *pev)
 {
 	char buf[64] = "";
 	int i, ret;
@@ -1588,14 +1622,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 
 static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 					  struct probe_trace_event **tevs,
-					  int max_tevs)
+					  int max_tevs, const char *module)
 {
 	struct symbol *sym;
 	int ret = 0, i;
 	struct probe_trace_event *tev;
 
 	/* Convert perf_probe_event with debuginfo */
-	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs);
+	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
 	if (ret != 0)
 		return ret;
 
@@ -1644,8 +1678,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 	}
 
 	/* Currently just checking function name from symbol map */
-	sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
-				       tev->point.symbol, NULL);
+	sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
 	if (!sym) {
 		pr_warning("Kernel symbol \'%s\' not found.\n",
 			   tev->point.symbol);
@@ -1668,7 +1701,7 @@ struct __event_package {
 };
 
 int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
-			  int max_tevs, bool force_add)
+			  int max_tevs, const char *module, bool force_add)
 {
 	int i, j, ret;
 	struct __event_package *pkgs;
@@ -1689,7 +1722,9 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
 		pkgs[i].pev = &pevs[i];
 		/* Convert with or without debuginfo */
 		ret  = convert_to_probe_trace_events(pkgs[i].pev,
-						      &pkgs[i].tevs, max_tevs);
+						     &pkgs[i].tevs,
+						     max_tevs,
+						     module);
 		if (ret < 0)
 			goto end;
 		pkgs[i].ntevs = ret;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index c74b1fd..5accbed 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -115,14 +115,18 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev);
 /* Command string to line-range */
 extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
 
+/* Internal use: Return kernel/module path */
+extern const char *kernel_get_module_path(const char *module);
 
 extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
-				 int max_probe_points, bool force_add);
+				 int max_probe_points, const char *module,
+				 bool force_add);
 extern int del_perf_probe_events(struct strlist *dellist);
 extern int show_perf_probe_events(void);
-extern int show_line_range(struct line_range *lr);
+extern int show_line_range(struct line_range *lr, const char *module);
 extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
-			       int max_probe_points, bool externs);
+			       int max_probe_points, const char *module,
+			       bool externs);
 
 
 /* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index a274fd0..c20bd52 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -116,6 +116,101 @@ static void line_list__free(struct list_head *head)
 	}
 }
 
+/* Dwarf FL wrappers */
+
+static int __linux_kernel_find_elf(Dwfl_Module *mod,
+				   void **userdata,
+				   const char *module_name,
+				   Dwarf_Addr base,
+				   char **file_name, Elf **elfp)
+{
+	int fd;
+	const char *path = kernel_get_module_path(module_name);
+
+	if (path) {
+		fd = open(path, O_RDONLY);
+		if (fd >= 0) {
+			*file_name = strdup(path);
+			return fd;
+		}
+	}
+	/* If failed, try to call standard method */
+	return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
+					  file_name, elfp);
+}
+
+static char *debuginfo_path;	/* Currently dummy */
+
+static const Dwfl_Callbacks offline_callbacks = {
+	.find_debuginfo = dwfl_standard_find_debuginfo,
+	.debuginfo_path = &debuginfo_path,
+
+	.section_address = dwfl_offline_section_address,
+
+	/* We use this table for core files too.  */
+	.find_elf = dwfl_build_id_find_elf,
+};
+
+static const Dwfl_Callbacks kernel_callbacks = {
+	.find_debuginfo = dwfl_standard_find_debuginfo,
+	.debuginfo_path = &debuginfo_path,
+
+	.find_elf = __linux_kernel_find_elf,
+	.section_address = dwfl_linux_kernel_module_section_address,
+};
+
+/* Get a Dwarf from offline image */
+static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
+{
+	Dwfl_Module *mod;
+	Dwarf *dbg = NULL;
+
+	if (!dwflp)
+		return NULL;
+
+	*dwflp = dwfl_begin(&offline_callbacks);
+	if (!*dwflp)
+		return NULL;
+
+	mod = dwfl_report_offline(*dwflp, "", "", fd);
+	if (!mod)
+		goto error;
+
+	dbg = dwfl_module_getdwarf(mod, bias);
+	if (!dbg) {
+error:
+		dwfl_end(*dwflp);
+		*dwflp = NULL;
+	}
+	return dbg;
+}
+
+/* Get a Dwarf from live kernel image */
+static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
+					  Dwarf_Addr *bias)
+{
+	Dwarf *dbg;
+
+	if (!dwflp)
+		return NULL;
+
+	*dwflp = dwfl_begin(&kernel_callbacks);
+	if (!*dwflp)
+		return NULL;
+
+	/* Load the kernel dwarves: Don't care the result here */
+	dwfl_linux_kernel_report_kernel(*dwflp);
+	dwfl_linux_kernel_report_modules(*dwflp);
+
+	dbg = dwfl_addrdwarf(*dwflp, addr, bias);
+	/* Here, check whether we could get a real dwarf */
+	if (!dbg) {
+		dwfl_end(*dwflp);
+		*dwflp = NULL;
+	}
+	return dbg;
+}
+
 /* Dwarf wrappers */
 
 /* Find the realpath of the target file. */
@@ -1177,10 +1272,12 @@ static int find_probes(int fd, struct probe_finder *pf)
 	Dwarf_Off off, noff;
 	size_t cuhl;
 	Dwarf_Die *diep;
-	Dwarf *dbg;
+	Dwarf *dbg = NULL;
+	Dwfl *dwfl;
+	Dwarf_Addr bias;	/* Currently ignored */
 	int ret = 0;
 
-	dbg = dwarf_begin(fd, DWARF_C_READ);
+	dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
 	if (!dbg) {
 		pr_warning("No dwarf info found in the vmlinux - "
 			"please rebuild with CONFIG_DEBUG_INFO=y.\n");
@@ -1221,7 +1318,8 @@ static int find_probes(int fd, struct probe_finder *pf)
 		off = noff;
 	}
 	line_list__free(&pf->lcache);
-	dwarf_end(dbg);
+	if (dwfl)
+		dwfl_end(dwfl);
 
 	return ret;
 }
@@ -1412,23 +1510,31 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev,
 }
 
 /* Reverse search */
-int find_perf_probe_point(int fd, unsigned long addr,
-			  struct perf_probe_point *ppt)
+int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
 {
 	Dwarf_Die cudie, spdie, indie;
-	Dwarf *dbg;
+	Dwarf *dbg = NULL;
+	Dwfl *dwfl = NULL;
 	Dwarf_Line *line;
-	Dwarf_Addr laddr, eaddr;
+	Dwarf_Addr laddr, eaddr, bias = 0;
 	const char *tmp;
 	int lineno, ret = 0;
 	bool found = false;
 
-	dbg = dwarf_begin(fd, DWARF_C_READ);
-	if (!dbg)
-		return -EBADF;
+	/* Open the live linux kernel */
+	dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
+	if (!dbg) {
+		pr_warning("No dwarf info found in the vmlinux - "
+			"please rebuild with CONFIG_DEBUG_INFO=y.\n");
+		ret = -EINVAL;
+		goto end;
+	}
 
+	/* Adjust address with bias */
+	addr += bias;
 	/* Find cu die */
-	if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) {
+	if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
+		pr_warning("No CU DIE is found at %lx\n", addr);
 		ret = -EINVAL;
 		goto end;
 	}
@@ -1491,7 +1597,8 @@ found:
 	}
 
 end:
-	dwarf_end(dbg);
+	if (dwfl)
+		dwfl_end(dwfl);
 	if (ret >= 0)
 		ret = found ? 1 : 0;
 	return ret;
@@ -1624,6 +1731,8 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
 	struct line_finder *lf = param->data;
 	struct line_range *lr = lf->lr;
 
+	pr_debug("find (%lx) %s\n", dwarf_dieoffset(sp_die),
+		 dwarf_diename(sp_die));
 	if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
 	    die_compare_name(sp_die, lr->function)) {
 		lf->fname = dwarf_decl_file(sp_die);
@@ -1667,10 +1776,12 @@ int find_line_range(int fd, struct line_range *lr)
 	Dwarf_Off off = 0, noff;
 	size_t cuhl;
 	Dwarf_Die *diep;
-	Dwarf *dbg;
+	Dwarf *dbg = NULL;
+	Dwfl *dwfl;
+	Dwarf_Addr bias;	/* Currently ignored */
 	const char *comp_dir;
 
-	dbg = dwarf_begin(fd, DWARF_C_READ);
+	dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
 	if (!dbg) {
 		pr_warning("No dwarf info found in the vmlinux - "
 			"please rebuild with CONFIG_DEBUG_INFO=y.\n");
@@ -1716,8 +1827,7 @@ int find_line_range(int fd, struct line_range *lr)
 	}
 
 	pr_debug("path: %s\n", lr->path);
-	dwarf_end(dbg);
-
+	dwfl_end(dwfl);
 	return (ret < 0) ? ret : lf.found;
 }
 
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 516912a..bba69d4 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -22,7 +22,7 @@ extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
 				    int max_tevs);
 
 /* Find a perf_probe_point from debuginfo */
-extern int find_perf_probe_point(int fd, unsigned long addr,
+extern int find_perf_probe_point(unsigned long addr,
 				 struct perf_probe_point *ppt);
 
 /* Find a line range */
@@ -35,6 +35,7 @@ extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
 
 #include <dwarf.h>
 #include <libdw.h>
+#include <libdwfl.h>
 #include <version.h>
 
 struct probe_finder {

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

end of thread, other threads:[~2010-10-23 19:42 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-10-21 10:12 [PATCH -tip 0/7] Perf probe update (--vars/--module) Masami Hiramatsu
2010-10-21 10:13 ` [PATCH -tip 1/7] [BUGFIX] perf probe: Fix type searching Masami Hiramatsu
2010-10-23 19:40   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
2010-10-21 10:13 ` [PATCH -tip 2/7] [BUGFIX] perf probe: Fix local variable searching loop Masami Hiramatsu
2010-10-23 19:40   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
2010-10-21 10:13 ` [PATCH -tip 3/7] perf probe: Support global variables Masami Hiramatsu
2010-10-23 19:40   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
2010-10-21 10:13 ` [PATCH -tip 4/7] perf probe: Show accessible local variables Masami Hiramatsu
2010-10-23 19:41   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
2010-10-21 10:13 ` [PATCH -tip 5/7] perf probe: Function style fix Masami Hiramatsu
2010-10-23 19:41   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
2010-10-21 10:13 ` [PATCH -tip 6/7] perf probe: Show accessible global variables Masami Hiramatsu
2010-10-21 20:50   ` Arnaldo Carvalho de Melo
2010-10-22  2:25     ` Masami Hiramatsu
2010-10-22  5:31       ` Masami Hiramatsu
2010-10-23 19:42   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu
2010-10-21 10:13 ` [PATCH -tip 7/7] perf probe: Add basic module support Masami Hiramatsu
2010-10-23 19:42   ` [tip:perf/urgent] " tip-bot for Masami Hiramatsu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox