All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo
@ 2014-02-06  5:32 Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 01/11] [BUGFIX] perf-probe: Fix to do exit call for symbol maps Masami Hiramatsu
                   ` (11 more replies)
  0 siblings, 12 replies; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-06  5:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Hi,

Here is the 3rd version of the series for handling local
functions correctly with perf-probe. This version also
includes distro debuginfo-file support (a small
enhancement, based on existing feature).

In this version, I used ref_reloc_sym based probe point
instead of absolute address/"_stext", because kASLR
changes the address offset randomly and the debuginfo
doesn't know that offset. Recently perftools supports
kASLR by introducing ref_reloc_sym (which is usually
"_text" or "_stext"). Since we already ensured that
the kmap->ref_reloc_sym symbol exists in the kernel,
it is safe to reuse it for the reference point of
probe points.

Note that this series requires a bugfix patch:
  perf-probe: Do not add offset to uprobe address
  https://lkml.org/lkml/2014/2/5/7


Issue 1)
 Current perf-probe can't handle probe-points for kprobes,
 since it uses symbol-based probe definition. The symbol
 based definition is easy to read and robust for differnt
 kernel and modules. However, when user gives a local
 function name which has several different instances,
 it may put probes on wrong (or unexpected) address.
 On the other hand, since uprobe events are based on the
 actual address, it can avoid this issue.

 E.g.
In the case to probe t_show local functions (which has
4 different instances.
  ----
  # grep " t_show\$" /proc/kallsyms
  ffffffff810d9720 t t_show
  ffffffff810e2e40 t t_show
  ffffffff810ece30 t t_show
  ffffffff810f4ad0 t t_show
  # ./perf probe -fa "t_show \$vars"
  Added new events:
    probe:t_show         (on t_show with $vars)
    probe:t_show_1       (on t_show with $vars)
    probe:t_show_2       (on t_show with $vars)
    probe:t_show_3       (on t_show with $vars)

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

          perf record -e probe:t_show_3 -aR sleep 1
  ----
OK, we have 4 different t_show()s. All functions have
different arguments as below;
  ----
  # cat /sys/kernel/debug/tracing/kprobe_events
  p:probe/t_show t_show m=%di:u64 v=%si:u64
  p:probe/t_show_1 t_show m=%di:u64 v=%si:u64 t=%si:u64
  p:probe/t_show_2 t_show m=%di:u64 v=%si:u64 fmt=%si:u64
  p:probe/t_show_3 t_show m=%di:u64 v=%si:u64 file=%si:u64
  ----
However, all of them have been put on the *same* address.
  ----
  # cat /sys/kernel/debug/kprobes/list
  ffffffff810d9720  k  t_show+0x0    [DISABLED]
  ffffffff810d9720  k  t_show+0x0    [DISABLED]
  ffffffff810d9720  k  t_show+0x0    [DISABLED]
  ffffffff810d9720  k  t_show+0x0    [DISABLED]
  ----
 oops...

Issue 2)
 With the debuginfo, issue 1 can be solved by using
 _stext-based probe definition instead of local symbol-based.
 However, without debuginfo, perf-probe can only use
 symbol-map in the binary (or kallsyms). The map provides
 symbol find methods, but it returns only the first matched
 symbol. To put probes on all functions which have given
 symbol, we need a symbol-list iterator for the map.

 E.g. (built perf with NO_DWARF=1)
In the case to probe t_show and identity__map_ip in perf.
  ----
  # ./perf probe -a t_show
  Added new event:
    probe:t_show         (on t_show)

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

          perf record -e probe:t_show -aR sleep 1

  # ./perf probe -x perf -a identity__map_ip
  no symbols found in /kbuild/ksrc/linux-3/tools/perf/perf, maybe install a debug package?
  Failed to load map.
    Error: Failed to add events. (-22)
  ----
 oops.....


Solutions)
To solve the issue 1, this series changes perf probe to
use _stext-based probe definition. This means that we
also need to fix the --list options to analyze actual
probe address from _stext address. (and that has been
done in this series).

E.g. with this series;
  ----
  # ./perf probe -a "t_show \$vars"
  Added new events:
    probe:t_show         (on t_show with $vars)
    probe:t_show_1       (on t_show with $vars)
    probe:t_show_2       (on t_show with $vars)
    probe:t_show_3       (on t_show with $vars)

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

          perf record -e probe:t_show_3 -aR sleep 1

  # cat /sys/kernel/debug/tracing/kprobe_events
  p:probe/t_show _stext+889880 m=%di:u64 v=%si:u64
  p:probe/t_show_1 _stext+928568 m=%di:u64 v=%si:u64 t=%si:u64
  p:probe/t_show_2 _stext+969512 m=%di:u64 v=%si:u64 fmt=%si:u64
  p:probe/t_show_3 _stext+1001416 m=%di:u64 v=%si:u64 file=%si:u64

  # cat /sys/kernel/debug/kprobes/list
  ffffffffb50d95e0  k  t_show+0x0    [DISABLED]
  ffffffffb50e2d00  k  t_show+0x0    [DISABLED]
  ffffffffb50f4990  k  t_show+0x0    [DISABLED]
  ffffffffb50eccf0  k  t_show+0x0    [DISABLED]
  ----
This time we can see the events are set in different
addresses.

And for the issue 2, the last patch introduces symbol
iterators for map, dso and symbols (since the symbol
list is the symbols and it is included in dso, and perf
probe accesses dso via map).

E.g. with this series (built perf with NO_DWARF=1);
  ----
  # ./perf probe -a t_show
  Added new events:
    probe:t_show         (on t_show)
    probe:t_show_1       (on t_show)
    probe:t_show_2       (on t_show)
    probe:t_show_3       (on t_show)

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

          perf record -e probe:t_show_3 -aR sleep 1

  # ./perf probe -x perf -a identity__map_ip
  Added new events:
    probe_perf:identity__map_ip (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
    probe_perf:identity__map_ip_1 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
    probe_perf:identity__map_ip_2 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
    probe_perf:identity__map_ip_3 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)

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

          perf record -e probe_perf:identity__map_ip_3 -aR sleep 1
  ----
Now, even without the debuginfo, both the kprobe and
uprobe are set 4 different places correctly.

BTW, while testing above, I've found some bugs and
another minor issue; perf-probe doesn't show the
modules and binaries in which probes are set.
I've also fixed it in this series as below.

Without the fix;

  # ./perf probe -m drm drm_av_sync_delay
  # ./perf probe -x perf dso__load_vmlinux

  # ./perf probe -l
    probe:drm_av_sync_delay (on drm_av_sync_delay)
    probe_perf:dso__load_vmlinux (on 0x000000000006d110)

With this fix;

  # ./perf probe -l
    probe:drm_av_sync_delay (on drm_av_sync_delay in drm)
    probe_perf:dso__load_vmlinux (on 0x000000000006d110 in /kbuild/ksrc/linux-3/tools/perf/perf)

Changes from v2:
 - Use ref_reloc_sym instead of "_stext" for reference point.
   (Thanks for Namhyung Kim!)
 - Add 2 cleanup patches for reducing the redundant features.
 - Add distro-style debuginfo support.

TODO:
 - Support local functions in modules. This requires kernel
 side enhancement to allow setting probes by the relative
 addresses in modules too.
 - Uprobe-event MUST traces the change of given binary even
 when the event is disabled. I've found that user can replace
 the target binary after setting events and the events can be
 enabled on the different instructions...

---

Masami Hiramatsu (11):
      [BUGFIX] perf-probe: Fix to do exit call for symbol maps
      [CLEANUP] perf-probe: Remove incorrect symbol check for --list
      [CLEANUP] perf-probe: Replace line_list with intlist
      [CLEANUP] perf-probe: Unify show_available_functions for uprobes/kprobes
      perf-probe: Show in what binaries/modules probes are set
      perf-probe: Use ref_reloc_sym based address instead of the symbol name
      perf-probe: Find given address from offline dwarf
      perf-probe: Show appropriate symbol for ref_reloc_sym based kprobes
      perf-probe: Show source-level or symbol-level info for uprobes
      perf-probe: Allow to add events on the local functions
      perf probe: Support distro-style debuginfo for uprobe


 tools/perf/builtin-probe.c     |   12 -
 tools/perf/util/dso.h          |   10 
 tools/perf/util/map.h          |   10 
 tools/perf/util/probe-event.c  |  863 ++++++++++++++++++++++------------------
 tools/perf/util/probe-event.h  |   12 -
 tools/perf/util/probe-finder.c |  198 ++-------
 tools/perf/util/probe-finder.h |    5 
 tools/perf/util/symbol.h       |   11 +
 8 files changed, 566 insertions(+), 555 deletions(-)

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


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

* [PATCH -tip v3 01/11] [BUGFIX] perf-probe: Fix to do exit call for symbol maps
  2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
@ 2014-02-06  5:32 ` Masami Hiramatsu
  2014-02-17  7:56   ` Namhyung Kim
  2014-02-22 17:59   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 02/11] [CLEANUP] perf-probe: Remove incorrect symbol check for --list Masami Hiramatsu
                   ` (10 subsequent siblings)
  11 siblings, 2 replies; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-06  5:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Some perf-probe commands do symbol_init() but doesn't
do exit call. This fixes that to call symbol_exit()
and releases machine if needed.
This also merges init_vmlinux() and init_user_exec()
because both of them are doing similar things.
(init_user_exec() just skips init vmlinux related
 symbol maps)

Changes from v2:
 - Not to set symbol_conf.try_vmlinux_path in init_symbol_maps()
   (Thanks to Namhyung Kim!)

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/probe-event.c |  104 ++++++++++++++++++++++-------------------
 1 file changed, 56 insertions(+), 48 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index d8b048c..9aa7783 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -73,31 +73,31 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
 static int convert_name_to_addr(struct perf_probe_event *pev,
 				const char *exec);
 static void clear_probe_trace_event(struct probe_trace_event *tev);
-static struct machine machine;
+static struct machine *host_machine;
 
 /* Initialize symbol maps and path of vmlinux/modules */
-static int init_vmlinux(void)
+static int init_symbol_maps(bool user_only)
 {
 	int ret;
 
 	symbol_conf.sort_by_name = true;
-	if (symbol_conf.vmlinux_name == NULL)
-		symbol_conf.try_vmlinux_path = true;
-	else
-		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
 	ret = symbol__init();
 	if (ret < 0) {
 		pr_debug("Failed to init symbol map.\n");
 		goto out;
 	}
 
-	ret = machine__init(&machine, "", HOST_KERNEL_ID);
-	if (ret < 0)
-		goto out;
+	if (host_machine || user_only)	/* already initialized */
+		return 0;
 
-	if (machine__create_kernel_maps(&machine) < 0) {
-		pr_debug("machine__create_kernel_maps() failed.\n");
-		goto out;
+	if (symbol_conf.vmlinux_name)
+		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
+
+	host_machine = machine__new_host();
+	if (!host_machine) {
+		pr_debug("machine__new_host() failed.\n");
+		symbol__exit();
+		ret = -1;
 	}
 out:
 	if (ret < 0)
@@ -105,21 +105,30 @@ out:
 	return ret;
 }
 
+static void exit_symbol_maps(void)
+{
+	if (host_machine) {
+		machine__delete(host_machine);
+		host_machine = NULL;
+	}
+	symbol__exit();
+}
+
 static struct symbol *__find_kernel_function_by_name(const char *name,
 						     struct map **mapp)
 {
-	return machine__find_kernel_function_by_name(&machine, name, mapp,
+	return machine__find_kernel_function_by_name(host_machine, name, mapp,
 						     NULL);
 }
 
 static struct map *kernel_get_module_map(const char *module)
 {
 	struct rb_node *nd;
-	struct map_groups *grp = &machine.kmaps;
+	struct map_groups *grp = &host_machine->kmaps;
 
 	/* A file path -- this is an offline module */
 	if (module && strchr(module, '/'))
-		return machine__new_module(&machine, 0, module);
+		return machine__new_module(host_machine, 0, module);
 
 	if (!module)
 		module = "kernel";
@@ -141,7 +150,7 @@ static struct dso *kernel_get_module_dso(const char *module)
 	const char *vmlinux_name;
 
 	if (module) {
-		list_for_each_entry(dso, &machine.kernel_dsos, node) {
+		list_for_each_entry(dso, &host_machine->kernel_dsos, node) {
 			if (strncmp(dso->short_name + 1, module,
 				    dso->short_name_len - 2) == 0)
 				goto found;
@@ -150,7 +159,7 @@ static struct dso *kernel_get_module_dso(const char *module)
 		return NULL;
 	}
 
-	map = machine.vmlinux_maps[MAP__FUNCTION];
+	map = host_machine->vmlinux_maps[MAP__FUNCTION];
 	dso = map->dso;
 
 	vmlinux_name = symbol_conf.vmlinux_name;
@@ -173,20 +182,6 @@ const char *kernel_get_module_path(const char *module)
 	return (dso) ? dso->long_name : NULL;
 }
 
-static int init_user_exec(void)
-{
-	int ret = 0;
-
-	symbol_conf.try_vmlinux_path = false;
-	symbol_conf.sort_by_name = true;
-	ret = symbol__init();
-
-	if (ret < 0)
-		pr_debug("Failed to init symbol map.\n");
-
-	return ret;
-}
-
 static int convert_exec_to_group(const char *exec, char **result)
 {
 	char *ptr1, *ptr2, *exec_copy;
@@ -563,7 +558,7 @@ static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
  * Show line-range always requires debuginfo to find source file and
  * line number.
  */
-int show_line_range(struct line_range *lr, const char *module)
+static int __show_line_range(struct line_range *lr, const char *module)
 {
 	int l = 1;
 	struct line_node *ln;
@@ -573,10 +568,6 @@ int show_line_range(struct line_range *lr, const char *module)
 	char *tmp;
 
 	/* Search a line range */
-	ret = init_vmlinux();
-	if (ret < 0)
-		return ret;
-
 	dinfo = open_debuginfo(module);
 	if (!dinfo) {
 		pr_warning("Failed to open debuginfo file.\n");
@@ -646,6 +637,19 @@ end:
 	return ret;
 }
 
+int show_line_range(struct line_range *lr, const char *module)
+{
+	int ret;
+
+	ret = init_symbol_maps(false);
+	if (ret < 0)
+		return ret;
+	ret = __show_line_range(lr, module);
+	exit_symbol_maps();
+
+	return ret;
+}
+
 static int show_available_vars_at(struct debuginfo *dinfo,
 				  struct perf_probe_event *pev,
 				  int max_vls, struct strfilter *_filter,
@@ -707,14 +711,15 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
 	int i, ret = 0;
 	struct debuginfo *dinfo;
 
-	ret = init_vmlinux();
+	ret = init_symbol_maps(false);
 	if (ret < 0)
 		return ret;
 
 	dinfo = open_debuginfo(module);
 	if (!dinfo) {
 		pr_warning("Failed to open debuginfo file.\n");
-		return -ENOENT;
+		ret = -ENOENT;
+		goto out;
 	}
 
 	setup_pager();
@@ -724,6 +729,8 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
 					     externs);
 
 	debuginfo__delete(dinfo);
+out:
+	exit_symbol_maps();
 	return ret;
 }
 
@@ -1807,7 +1814,7 @@ int show_perf_probe_events(void)
 	if (fd < 0)
 		return fd;
 
-	ret = init_vmlinux();
+	ret = init_symbol_maps(false);
 	if (ret < 0)
 		return ret;
 
@@ -1820,6 +1827,7 @@ int show_perf_probe_events(void)
 		close(fd);
 	}
 
+	exit_symbol_maps();
 	return ret;
 }
 
@@ -2135,12 +2143,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
 	if (pkgs == NULL)
 		return -ENOMEM;
 
-	if (!pevs->uprobes)
-		/* Init vmlinux path */
-		ret = init_vmlinux();
-	else
-		ret = init_user_exec();
-
+	ret = init_symbol_maps(pevs->uprobes);
 	if (ret < 0) {
 		free(pkgs);
 		return ret;
@@ -2174,6 +2177,7 @@ end:
 		zfree(&pkgs[i].tevs);
 	}
 	free(pkgs);
+	exit_symbol_maps();
 
 	return ret;
 }
@@ -2347,7 +2351,7 @@ static int available_kernel_funcs(const char *module)
 	struct map *map;
 	int ret;
 
-	ret = init_vmlinux();
+	ret = init_symbol_maps(false);
 	if (ret < 0)
 		return ret;
 
@@ -2356,7 +2360,10 @@ static int available_kernel_funcs(const char *module)
 		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
 		return -EINVAL;
 	}
-	return __show_available_funcs(map);
+	ret = __show_available_funcs(map);
+	exit_symbol_maps();
+
+	return ret;
 }
 
 static int available_user_funcs(const char *target)
@@ -2364,7 +2371,7 @@ static int available_user_funcs(const char *target)
 	struct map *map;
 	int ret;
 
-	ret = init_user_exec();
+	ret = init_symbol_maps(true);
 	if (ret < 0)
 		return ret;
 
@@ -2372,6 +2379,7 @@ static int available_user_funcs(const char *target)
 	ret = __show_available_funcs(map);
 	dso__delete(map->dso);
 	map__delete(map);
+	exit_symbol_maps();
 	return ret;
 }
 



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

* [PATCH -tip v3 02/11] [CLEANUP] perf-probe: Remove incorrect symbol check for --list
  2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 01/11] [BUGFIX] perf-probe: Fix to do exit call for symbol maps Masami Hiramatsu
@ 2014-02-06  5:32 ` Masami Hiramatsu
  2014-02-22 18:00   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 03/11] [CLEANUP] perf-probe: Replace line_list with intlist Masami Hiramatsu
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-06  5:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Remove unneeded symbol check for --list option.
This code actually checks whether the given symbol exists
in the kernel. But this is incorrect for online kernel/module
and offline module too.
 - For online kernel/module, the kprobes itself already
  ensured the symbol exist in the kernel.
 - For offline module, this code can't access the offlined
  modules. Ignore it.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/probe-event.c |    8 --------
 1 file changed, 8 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 9aa7783..a4649e7 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -739,14 +739,6 @@ out:
 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 					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;
-	}
-
 	return convert_to_perf_probe_point(tp, pp);
 }
 



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

* [PATCH -tip v3 03/11] [CLEANUP] perf-probe: Replace line_list with intlist
  2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 01/11] [BUGFIX] perf-probe: Fix to do exit call for symbol maps Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 02/11] [CLEANUP] perf-probe: Remove incorrect symbol check for --list Masami Hiramatsu
@ 2014-02-06  5:32 ` Masami Hiramatsu
  2014-02-17  7:58   ` Namhyung Kim
  2014-02-22 18:00   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 04/11] [CLEANUP] perf-probe: Unify show_available_functions for uprobes/kprobes Masami Hiramatsu
                   ` (8 subsequent siblings)
  11 siblings, 2 replies; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-06  5:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Replace line_list (struct line_node) with intlist for
reducing similar codes.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/builtin-probe.c     |   12 +++---
 tools/perf/util/probe-event.c  |   22 +++++------
 tools/perf/util/probe-event.h  |   12 +-----
 tools/perf/util/probe-finder.c |   81 ++++++----------------------------------
 tools/perf/util/probe-finder.h |    3 +
 5 files changed, 35 insertions(+), 95 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 7894888..cdcd4eb 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -268,9 +268,9 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
 	return 0;
 }
 
-static void init_params(void)
+static int init_params(void)
 {
-	line_range__init(&params.line_range);
+	return line_range__init(&params.line_range);
 }
 
 static void cleanup_params(void)
@@ -515,9 +515,11 @@ int cmd_probe(int argc, const char **argv, const char *prefix)
 {
 	int ret;
 
-	init_params();
-	ret = __cmd_probe(argc, argv, prefix);
-	cleanup_params();
+	ret = init_params();
+	if (!ret) {
+		ret = __cmd_probe(argc, argv, prefix);
+		cleanup_params();
+	}
 
 	return ret;
 }
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index a4649e7..f70fd08 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -561,7 +561,7 @@ static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
 static int __show_line_range(struct line_range *lr, const char *module)
 {
 	int l = 1;
-	struct line_node *ln;
+	struct int_node *ln;
 	struct debuginfo *dinfo;
 	FILE *fp;
 	int ret;
@@ -614,8 +614,8 @@ static int __show_line_range(struct line_range *lr, const char *module)
 			goto end;
 	}
 
-	list_for_each_entry(ln, &lr->line_list, list) {
-		for (; ln->line > l; l++) {
+	intlist__for_each(ln, lr->line_list) {
+		for (; ln->i > l; l++) {
 			ret = show_one_line(fp, l - lr->offset);
 			if (ret < 0)
 				goto end;
@@ -775,24 +775,22 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
 
 void line_range__clear(struct line_range *lr)
 {
-	struct line_node *ln;
-
 	free(lr->function);
 	free(lr->file);
 	free(lr->path);
 	free(lr->comp_dir);
-	while (!list_empty(&lr->line_list)) {
-		ln = list_first_entry(&lr->line_list, struct line_node, list);
-		list_del(&ln->list);
-		free(ln);
-	}
+	intlist__delete(lr->line_list);
 	memset(lr, 0, sizeof(*lr));
 }
 
-void line_range__init(struct line_range *lr)
+int line_range__init(struct line_range *lr)
 {
 	memset(lr, 0, sizeof(*lr));
-	INIT_LIST_HEAD(&lr->line_list);
+	lr->line_list = intlist__new(NULL);
+	if (!lr->line_list)
+		return -ENOMEM;
+	else
+		return 0;
 }
 
 static int parse_line_num(char **ptr, int *val, const char *what)
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index fcaf727..776c934 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -2,6 +2,7 @@
 #define _PROBE_EVENT_H
 
 #include <stdbool.h>
+#include "intlist.h"
 #include "strlist.h"
 #include "strfilter.h"
 
@@ -76,13 +77,6 @@ struct perf_probe_event {
 	struct perf_probe_arg	*args;	/* Arguments */
 };
 
-
-/* Line number container */
-struct line_node {
-	struct list_head	list;
-	int			line;
-};
-
 /* Line range */
 struct line_range {
 	char			*file;		/* File name */
@@ -92,7 +86,7 @@ struct line_range {
 	int			offset;		/* Start line offset */
 	char			*path;		/* Real path name */
 	char			*comp_dir;	/* Compile directory */
-	struct list_head	line_list;	/* Visible lines */
+	struct intlist		*line_list;	/* Visible lines */
 };
 
 /* List of variables */
@@ -124,7 +118,7 @@ extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
 extern void line_range__clear(struct line_range *lr);
 
 /* Initialize line range */
-extern void line_range__init(struct line_range *lr);
+extern int line_range__init(struct line_range *lr);
 
 /* Internal use: Return kernel/module path */
 extern const char *kernel_get_module_path(const char *module);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 061edb1..e5e589f 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -35,6 +35,7 @@
 #include <linux/bitops.h>
 #include "event.h"
 #include "debug.h"
+#include "intlist.h"
 #include "util.h"
 #include "symbol.h"
 #include "probe-finder.h"
@@ -42,65 +43,6 @@
 /* Kprobe tracer basic type is up to u64 */
 #define MAX_BASIC_TYPE_BITS	64
 
-/* Line number list operations */
-
-/* Add a line to line number list */
-static int line_list__add_line(struct list_head *head, int line)
-{
-	struct line_node *ln;
-	struct list_head *p;
-
-	/* Reverse search, because new line will be the last one */
-	list_for_each_entry_reverse(ln, head, list) {
-		if (ln->line < line) {
-			p = &ln->list;
-			goto found;
-		} else if (ln->line == line)	/* Already exist */
-			return 1;
-	}
-	/* List is empty, or the smallest entry */
-	p = head;
-found:
-	pr_debug("line list: add a line %u\n", line);
-	ln = zalloc(sizeof(struct line_node));
-	if (ln == NULL)
-		return -ENOMEM;
-	ln->line = line;
-	INIT_LIST_HEAD(&ln->list);
-	list_add(&ln->list, p);
-	return 0;
-}
-
-/* Check if the line in line number list */
-static int line_list__has_line(struct list_head *head, int line)
-{
-	struct line_node *ln;
-
-	/* Reverse search, because new line will be the last one */
-	list_for_each_entry(ln, head, list)
-		if (ln->line == line)
-			return 1;
-
-	return 0;
-}
-
-/* Init line number list */
-static void line_list__init(struct list_head *head)
-{
-	INIT_LIST_HEAD(head);
-}
-
-/* Free line number list */
-static void line_list__free(struct list_head *head)
-{
-	struct line_node *ln;
-	while (!list_empty(head)) {
-		ln = list_first_entry(head, struct line_node, list);
-		list_del(&ln->list);
-		free(ln);
-	}
-}
-
 /* Dwarf FL wrappers */
 static char *debuginfo_path;	/* Currently dummy */
 
@@ -880,7 +822,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
 }
 
 /* Find lines which match lazy pattern */
-static int find_lazy_match_lines(struct list_head *head,
+static int find_lazy_match_lines(struct intlist *list,
 				 const char *fname, const char *pat)
 {
 	FILE *fp;
@@ -901,7 +843,7 @@ static int find_lazy_match_lines(struct list_head *head,
 			line[len - 1] = '\0';
 
 		if (strlazymatch(line, pat)) {
-			line_list__add_line(head, linenum);
+			intlist__add(list, linenum);
 			count++;
 		}
 		linenum++;
@@ -924,7 +866,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
 	Dwarf_Die *sc_die, die_mem;
 	int ret;
 
-	if (!line_list__has_line(&pf->lcache, lineno) ||
+	if (!intlist__has_entry(pf->lcache, lineno) ||
 	    strtailcmp(fname, pf->fname) != 0)
 		return 0;
 
@@ -952,9 +894,9 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
 	int ret = 0;
 
-	if (list_empty(&pf->lcache)) {
+	if (intlist__empty(pf->lcache)) {
 		/* Matching lazy line pattern */
-		ret = find_lazy_match_lines(&pf->lcache, pf->fname,
+		ret = find_lazy_match_lines(pf->lcache, pf->fname,
 					    pf->pev->point.lazy_line);
 		if (ret <= 0)
 			return ret;
@@ -1096,7 +1038,9 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
 #endif
 
 	off = 0;
-	line_list__init(&pf->lcache);
+	pf->lcache = intlist__new(NULL);
+	if (!pf->lcache)
+		return -ENOMEM;
 
 	/* Fastpath: lookup by function name from .debug_pubnames section */
 	if (pp->function) {
@@ -1149,7 +1093,8 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
 	}
 
 found:
-	line_list__free(&pf->lcache);
+	intlist__delete(pf->lcache);
+	pf->lcache = NULL;
 
 	return ret;
 }
@@ -1537,7 +1482,7 @@ static int line_range_add_line(const char *src, unsigned int lineno,
 		if (lr->path == NULL)
 			return -ENOMEM;
 	}
-	return line_list__add_line(&lr->line_list, lineno);
+	return intlist__add(lr->line_list, lineno);
 }
 
 static int line_range_walk_cb(const char *fname, int lineno,
@@ -1565,7 +1510,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 
 	/* Update status */
 	if (ret >= 0)
-		if (!list_empty(&lf->lr->line_list))
+		if (!intlist__empty(lf->lr->line_list))
 			ret = lf->found = 1;
 		else
 			ret = 0;	/* Lines are not found */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index ffc33cd..592c4da 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include "util.h"
+#include "intlist.h"
 #include "probe-event.h"
 
 #define MAX_PROBE_BUFFER	1024
@@ -66,7 +67,7 @@ struct probe_finder {
 	const char		*fname;		/* Real file name */
 	Dwarf_Die		cu_die;		/* Current CU */
 	Dwarf_Die		sp_die;
-	struct list_head	lcache;		/* Line cache for lazy match */
+	struct intlist		*lcache;	/* Line cache for lazy match */
 
 	/* For variable searching */
 #if _ELFUTILS_PREREQ(0, 142)



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

* [PATCH -tip v3 04/11] [CLEANUP] perf-probe: Unify show_available_functions for uprobes/kprobes
  2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
                   ` (2 preceding siblings ...)
  2014-02-06  5:32 ` [PATCH -tip v3 03/11] [CLEANUP] perf-probe: Replace line_list with intlist Masami Hiramatsu
@ 2014-02-06  5:32 ` Masami Hiramatsu
  2014-02-22 18:00   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 05/11] perf-probe: Show in what binaries/modules probes are set Masami Hiramatsu
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-06  5:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Unify show_available_functions for uprobes/kprobes to cleanup
and reduce the code. This also improves error messages.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/probe-event.c |   72 +++++++++++++++--------------------------
 1 file changed, 26 insertions(+), 46 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f70fd08..ace3ba3 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2323,66 +2323,46 @@ static int filter_available_functions(struct map *map __maybe_unused,
 	return 1;
 }
 
-static int __show_available_funcs(struct map *map)
-{
-	if (map__load(map, filter_available_functions)) {
-		pr_err("Failed to load map.\n");
-		return -EINVAL;
-	}
-	if (!dso__sorted_by_name(map->dso, map->type))
-		dso__sort_by_name(map->dso, map->type);
-
-	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
-	return 0;
-}
-
-static int available_kernel_funcs(const char *module)
+int show_available_funcs(const char *target, struct strfilter *_filter,
+					bool user)
 {
 	struct map *map;
 	int ret;
 
-	ret = init_symbol_maps(false);
+	ret = init_symbol_maps(user);
 	if (ret < 0)
 		return ret;
 
-	map = kernel_get_module_map(module);
+	/* Get a symbol map */
+	if (user)
+		map = dso__new_map(target);
+	else
+		map = kernel_get_module_map(target);
 	if (!map) {
-		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
+		pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
 		return -EINVAL;
 	}
-	ret = __show_available_funcs(map);
-	exit_symbol_maps();
-
-	return ret;
-}
-
-static int available_user_funcs(const char *target)
-{
-	struct map *map;
-	int ret;
 
-	ret = init_symbol_maps(true);
-	if (ret < 0)
-		return ret;
-
-	map = dso__new_map(target);
-	ret = __show_available_funcs(map);
-	dso__delete(map->dso);
-	map__delete(map);
-	exit_symbol_maps();
-	return ret;
-}
-
-int show_available_funcs(const char *target, struct strfilter *_filter,
-					bool user)
-{
-	setup_pager();
+	/* Load symbols with given filter */
 	available_func_filter = _filter;
+	if (map__load(map, filter_available_functions)) {
+		pr_err("Failed to load symbols in %s\n", (target) ? : "kernel");
+		goto end;
+	}
+	if (!dso__sorted_by_name(map->dso, map->type))
+		dso__sort_by_name(map->dso, map->type);
 
-	if (!user)
-		return available_kernel_funcs(target);
+	/* Show all (filtered) symbols */
+	setup_pager();
+	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+end:
+	if (user) {
+		dso__delete(map->dso);
+		map__delete(map);
+	}
+	exit_symbol_maps();
 
-	return available_user_funcs(target);
+	return ret;
 }
 
 /*



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

* [PATCH -tip v3 05/11] perf-probe: Show in what binaries/modules probes are set
  2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
                   ` (3 preceding siblings ...)
  2014-02-06  5:32 ` [PATCH -tip v3 04/11] [CLEANUP] perf-probe: Unify show_available_functions for uprobes/kprobes Masami Hiramatsu
@ 2014-02-06  5:32 ` Masami Hiramatsu
  2014-02-22 18:00   ` [tip:perf/core] perf probe: Show in what binaries/ modules " tip-bot for Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 06/11] perf-probe: Use ref_reloc_sym based address instead of the symbol name Masami Hiramatsu
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-06  5:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Show the name of binary file or modules in which the probes
are set with --list option.

Without this change;

  # ./perf probe -m drm drm_av_sync_delay
  # ./perf probe -x perf dso__load_vmlinux

  # ./perf probe -l
    probe:drm_av_sync_delay (on drm_av_sync_delay)
    probe_perf:dso__load_vmlinux (on 0x000000000006d110)

With this change;

  # ./perf probe -l
    probe:drm_av_sync_delay (on drm_av_sync_delay in drm)
    probe_perf:dso__load_vmlinux (on 0x000000000006d110 in /kbuild/ksrc/linux-3/tools/perf/perf)

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/probe-event.c |   10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index ace3ba3..de9fe90 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1728,7 +1728,8 @@ static struct strlist *get_probe_trace_command_rawlist(int fd)
 }
 
 /* Show an event */
-static int show_perf_probe_event(struct perf_probe_event *pev)
+static int show_perf_probe_event(struct perf_probe_event *pev,
+				 const char *module)
 {
 	int i, ret;
 	char buf[128];
@@ -1744,6 +1745,8 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
 		return ret;
 
 	printf("  %-20s (on %s", buf, place);
+	if (module)
+		printf(" in %s", module);
 
 	if (pev->nargs > 0) {
 		printf(" with");
@@ -1781,7 +1784,8 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
 			ret = convert_to_perf_probe_event(&tev, &pev,
 								is_kprobe);
 			if (ret >= 0)
-				ret = show_perf_probe_event(&pev);
+				ret = show_perf_probe_event(&pev,
+							    tev.point.module);
 		}
 		clear_perf_probe_event(&pev);
 		clear_probe_trace_event(&tev);
@@ -1980,7 +1984,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 		group = pev->group;
 		pev->event = tev->event;
 		pev->group = tev->group;
-		show_perf_probe_event(pev);
+		show_perf_probe_event(pev, tev->point.module);
 		/* Trick here - restore current event/group */
 		pev->event = (char *)event;
 		pev->group = (char *)group;



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

* [PATCH -tip v3 06/11] perf-probe: Use ref_reloc_sym based address instead of the symbol name
  2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
                   ` (4 preceding siblings ...)
  2014-02-06  5:32 ` [PATCH -tip v3 05/11] perf-probe: Show in what binaries/modules probes are set Masami Hiramatsu
@ 2014-02-06  5:32 ` Masami Hiramatsu
  2014-02-22 18:00   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 07/11] perf-probe: Find given address from offline dwarf Masami Hiramatsu
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-06  5:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Since several local symbols can have same name (e.g. t_show),
we need to use the relative address from the symbol referred by
kmap->ref_reloc_sym instead of the target symbol name itself.
Because the kernel address space layout randomize (kASLR) changes
the absolute address of kernel symbols, we can't relay on the
absolute address.
Note that this works only with debuginfo.

E.g. without this change;
  ----
  # ./perf probe -a "t_show \$vars"
  Added new events:
    probe:t_show         (on t_show with $vars)
    probe:t_show_1       (on t_show with $vars)
    probe:t_show_2       (on t_show with $vars)
    probe:t_show_3       (on t_show with $vars)

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

          perf record -e probe:t_show_3 -aR sleep 1
  ----
OK, we have 4 different t_show()s. All functions have
different arguments as below;
  ----
  # cat /sys/kernel/debug/tracing/kprobe_events
  p:probe/t_show t_show m=%di:u64 v=%si:u64
  p:probe/t_show_1 t_show m=%di:u64 v=%si:u64 t=%si:u64
  p:probe/t_show_2 t_show m=%di:u64 v=%si:u64 fmt=%si:u64
  p:probe/t_show_3 t_show m=%di:u64 v=%si:u64 file=%si:u64
  ----
However, all of them have been put on the *same* address.
  ----
  # cat /sys/kernel/debug/kprobes/list
  ffffffff810d9720  k  t_show+0x0    [DISABLED]
  ffffffff810d9720  k  t_show+0x0    [DISABLED]
  ffffffff810d9720  k  t_show+0x0    [DISABLED]
  ffffffff810d9720  k  t_show+0x0    [DISABLED]
  ----

With this change;
  ----
  # ./perf probe -a "t_show \$vars"
  Added new events:
    probe:t_show         (on t_show with $vars)
    probe:t_show_1       (on t_show with $vars)
    probe:t_show_2       (on t_show with $vars)
    probe:t_show_3       (on t_show with $vars)

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

          perf record -e probe:t_show_3 -aR sleep 1

  # cat /sys/kernel/debug/tracing/kprobe_events
  p:probe/t_show _stext+889880 m=%di:u64 v=%si:u64
  p:probe/t_show_1 _stext+928568 m=%di:u64 v=%si:u64 t=%si:u64
  p:probe/t_show_2 _stext+969512 m=%di:u64 v=%si:u64 fmt=%si:u64
  p:probe/t_show_3 _stext+1001416 m=%di:u64 v=%si:u64 file=%si:u64

  # cat /sys/kernel/debug/kprobes/list
  ffffffffb50d95e0  k  t_show+0x0    [DISABLED]
  ffffffffb50e2d00  k  t_show+0x0    [DISABLED]
  ffffffffb50f4990  k  t_show+0x0    [DISABLED]
  ffffffffb50eccf0  k  t_show+0x0    [DISABLED]
  ----
This time, each event is put in different address
correctly.

Note that currently this doesn't support address-based
probe on modules (thus the probes on modules are symbol
based), since it requires relative address probe syntax
for kprobe-tracer, and it isn't implemented yet.

One more note, this allows us to put events on correct
address, but --list option should be updated to show
correct corresponding source code.

Changes from v2:
  - Refer kmap->ref_reloc_sym instead of "_stext".
  - Refer map->reloc to catch up the kASLR perf fix.

Changes from v1:
  - Use _stext relative address instead of actual
    absolute address recorded in debuginfo.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/probe-event.c |   58 +++++++++++++++++++++++++++++++++++------
 1 file changed, 49 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index de9fe90..1ce2cb9 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -383,6 +383,51 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
 	return ret;
 }
 
+static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
+{
+	/* kmap->ref_reloc_sym should be set if host_machine is initialized */
+	struct kmap *kmap;
+
+	kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
+	return kmap->ref_reloc_sym;
+}
+
+/* Post processing the probe events */
+static int post_process_probe_trace_events(struct probe_trace_event *tevs,
+					   int ntevs, const char *module,
+					   bool uprobe)
+{
+	struct ref_reloc_sym *reloc_sym;
+	char *tmp;
+	int i;
+
+	if (uprobe)
+		return add_exec_to_probe_trace_events(tevs, ntevs, module);
+
+	/* Note that currently ref_reloc_sym based probe is not for drivers */
+	if (module)
+		return add_module_to_probe_trace_events(tevs, ntevs, module);
+
+	reloc_sym = __kernel_get_ref_reloc_sym();
+	if (!reloc_sym) {
+		pr_warning("Relocated base symbol is not found!\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ntevs; i++) {
+		if (tevs[i].point.address) {
+			tmp = strdup(reloc_sym->name);
+			if (!tmp)
+				return -ENOMEM;
+			free(tevs[i].point.symbol);
+			tevs[i].point.symbol = tmp;
+			tevs[i].point.offset = tevs[i].point.address -
+					       reloc_sym->unrelocated_addr;
+		}
+	}
+	return 0;
+}
+
 static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
 {
 	int i;
@@ -411,21 +456,16 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 		return 0;
 	}
 
+	pr_debug("Try to find probe point from debuginfo.\n");
 	/* Searching trace events corresponding to a probe event */
 	ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs);
 
 	debuginfo__delete(dinfo);
 
 	if (ntevs > 0) {	/* Succeeded to find trace events */
-		pr_debug("find %d probe_trace_events.\n", ntevs);
-		if (target) {
-			if (pev->uprobes)
-				ret = add_exec_to_probe_trace_events(*tevs,
-						 ntevs, target);
-			else
-				ret = add_module_to_probe_trace_events(*tevs,
-						 ntevs, target);
-		}
+		pr_debug("Found %d probe_trace_events.\n", ntevs);
+		ret = post_process_probe_trace_events(*tevs, ntevs,
+							target, pev->uprobes);
 		if (ret < 0) {
 			clear_probe_trace_events(*tevs, ntevs);
 			zfree(tevs);



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

* [PATCH -tip v3 07/11] perf-probe: Find given address from offline dwarf
  2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
                   ` (5 preceding siblings ...)
  2014-02-06  5:32 ` [PATCH -tip v3 06/11] perf-probe: Use ref_reloc_sym based address instead of the symbol name Masami Hiramatsu
@ 2014-02-06  5:32 ` Masami Hiramatsu
  2014-02-22 18:00   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 08/11] perf-probe: Show appropriate symbol for ref_reloc_sym based kprobes Masami Hiramatsu
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-06  5:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Find the given address from offline dwarfs instead of
online kernel dwarfs.

On the KASLR enabled kernel, the kernel text section is
loaded with random offset, and the debuginfo__new_online_kernel
can't handle it. So let's move to the offline dwarf
loader instead of using the online dwarf loader.

As a result, since we don't need debuginfo__new_online_kernel
any more, this also removes the functions related that.

Without this change;

  # ./perf probe -l
    probe:t_show         (on _stext+901288 with m v)
    probe:t_show_1       (on _stext+939624 with m v t)
    probe:t_show_2       (on _stext+980296 with m v fmt)
    probe:t_show_3       (on _stext+1014392 with m v file)

With this change;

  # ./perf probe -l
    probe:t_show         (on t_show@linux-3/kernel/trace/ftrace.c with m v)
    probe:t_show_1       (on t_show@linux-3/kernel/trace/trace.c with m v t)
    probe:t_show_2       (on t_show@kernel/trace/trace_printk.c with m v fmt)
    probe:t_show_3       (on t_show@kernel/trace/trace_events.c with m v file)

Changes from v2:
 - Instead of retrying, directly opens offline dwarf.
 - Remove debuginfo__new_online_kernel and related functions.
 - Refer map->reloc to get the correct address of a symbol.
 - Add a special case for handling ref_reloc_sym based address.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/probe-event.c  |   40 ++++++++++++-------
 tools/perf/util/probe-finder.c |   86 ----------------------------------------
 tools/perf/util/probe-finder.h |    1 
 3 files changed, 26 insertions(+), 101 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1ce2cb9..8e34c8d 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -248,6 +248,18 @@ static struct debuginfo *open_debuginfo(const char *module)
 	return debuginfo__new(path);
 }
 
+static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
+{
+	/* kmap->ref_reloc_sym should be set if host_machine is initialized */
+	struct kmap *kmap;
+
+	if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0)
+		return NULL;
+
+	kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
+	return kmap->ref_reloc_sym;
+}
+
 /*
  * Convert trace point to probe point with debuginfo
  * Currently only handles kprobes.
@@ -256,18 +268,27 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 					struct perf_probe_point *pp)
 {
 	struct symbol *sym;
+	struct ref_reloc_sym *reloc_sym;
 	struct map *map;
-	u64 addr;
+	u64 addr = 0;
 	int ret = -ENOENT;
 	struct debuginfo *dinfo;
 
-	sym = __find_kernel_function_by_name(tp->symbol, &map);
-	if (sym) {
-		addr = map->unmap_ip(map, sym->start + tp->offset);
+	/* ref_reloc_sym is just a label. Need a special fix*/
+	reloc_sym = __kernel_get_ref_reloc_sym();
+	if (reloc_sym && strcmp(tp->symbol, reloc_sym->name) == 0)
+		addr = reloc_sym->unrelocated_addr + tp->offset;
+	else {
+		sym = __find_kernel_function_by_name(tp->symbol, &map);
+		if (sym)
+			addr = map->unmap_ip(map, sym->start + tp->offset) -
+				map->reloc;
+	}
+	if (addr) {
 		pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
 			 tp->offset, addr);
 
-		dinfo = debuginfo__new_online_kernel(addr);
+		dinfo = open_debuginfo(tp->module);
 		if (dinfo) {
 			ret = debuginfo__find_probe_point(dinfo,
 						 (unsigned long)addr, pp);
@@ -383,15 +404,6 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
 	return ret;
 }
 
-static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
-{
-	/* kmap->ref_reloc_sym should be set if host_machine is initialized */
-	struct kmap *kmap;
-
-	kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
-	return kmap->ref_reloc_sym;
-}
-
 /* Post processing the probe events */
 static int post_process_probe_trace_events(struct probe_trace_event *tevs,
 					   int ntevs, const char *module,
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index e5e589f..4f6e277 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -89,79 +89,6 @@ error:
 	return -ENOENT;
 }
 
-#if _ELFUTILS_PREREQ(0, 148)
-/* This method is buggy if elfutils is older than 0.148 */
-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);
-
-	pr_debug2("Use file %s for %s\n", 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 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 live kernel image */
-static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
-					       Dwarf_Addr addr)
-{
-	dbg->dwfl = dwfl_begin(&kernel_callbacks);
-	if (!dbg->dwfl)
-		return -EINVAL;
-
-	/* Load the kernel dwarves: Don't care the result here */
-	dwfl_linux_kernel_report_kernel(dbg->dwfl);
-	dwfl_linux_kernel_report_modules(dbg->dwfl);
-
-	dbg->dbg = dwfl_addrdwarf(dbg->dwfl, addr, &dbg->bias);
-	/* Here, check whether we could get a real dwarf */
-	if (!dbg->dbg) {
-		pr_debug("Failed to find kernel dwarf at %lx\n",
-			 (unsigned long)addr);
-		dwfl_end(dbg->dwfl);
-		memset(dbg, 0, sizeof(*dbg));
-		return -ENOENT;
-	}
-
-	return 0;
-}
-#else
-/* With older elfutils, this just support kernel module... */
-static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
-					       Dwarf_Addr addr __maybe_unused)
-{
-	const char *path = kernel_get_module_path("kernel");
-
-	if (!path) {
-		pr_err("Failed to find vmlinux path\n");
-		return -ENOENT;
-	}
-
-	pr_debug2("Use file %s for debuginfo\n", path);
-	return debuginfo__init_offline_dwarf(dbg, path);
-}
-#endif
-
 struct debuginfo *debuginfo__new(const char *path)
 {
 	struct debuginfo *dbg = zalloc(sizeof(*dbg));
@@ -174,19 +101,6 @@ struct debuginfo *debuginfo__new(const char *path)
 	return dbg;
 }
 
-struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
-{
-	struct debuginfo *dbg = zalloc(sizeof(*dbg));
-
-	if (!dbg)
-		return NULL;
-
-	if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0)
-		zfree(&dbg);
-
-	return dbg;
-}
-
 void debuginfo__delete(struct debuginfo *dbg)
 {
 	if (dbg) {
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 592c4da..3fc5973 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -31,7 +31,6 @@ struct debuginfo {
 };
 
 extern struct debuginfo *debuginfo__new(const char *path);
-extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr);
 extern void debuginfo__delete(struct debuginfo *dbg);
 
 /* Find probe_trace_events specified by perf_probe_event from debuginfo */



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

* [PATCH -tip v3 08/11] perf-probe: Show appropriate symbol for ref_reloc_sym based kprobes
  2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
                   ` (6 preceding siblings ...)
  2014-02-06  5:32 ` [PATCH -tip v3 07/11] perf-probe: Find given address from offline dwarf Masami Hiramatsu
@ 2014-02-06  5:32 ` Masami Hiramatsu
  2014-02-22 18:01   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 09/11] perf-probe: Show source-level or symbol-level info for uprobes Masami Hiramatsu
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-06  5:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Show appropriate symbol for ref_reloc_sym based kprobes instead
of refpoint+offset when perf-probe -l runs without debuginfo.

Without this change:
  # ./perf probe -l
    probe:t_show         (on _stext+889880 with m v)
    probe:t_show_1       (on _stext+928568 with m v t)
    probe:t_show_2       (on _stext+969512 with m v fmt)
    probe:t_show_3       (on _stext+1001416 with m v file)

With this change:
  # ./perf probe -l
    probe:t_show         (on t_show with m v)
    probe:t_show_1       (on t_show with m v t)
    probe:t_show_2       (on t_show with m v fmt)
    probe:t_show_3       (on t_show with m v file)

Changes from v2:
 - Check ref_reloc_sym to find correct unrelocated address.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/probe-event.c |   83 +++++++++++++++++++++++++++--------------
 1 file changed, 55 insertions(+), 28 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8e34c8d..f86820c 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -121,6 +121,42 @@ static struct symbol *__find_kernel_function_by_name(const char *name,
 						     NULL);
 }
 
+static struct symbol *__find_kernel_function(u64 addr, struct map **mapp)
+{
+	return machine__find_kernel_function(host_machine, addr, mapp, NULL);
+}
+
+static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void)
+{
+	/* kmap->ref_reloc_sym should be set if host_machine is initialized */
+	struct kmap *kmap;
+
+	if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0)
+		return NULL;
+
+	kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
+	return kmap->ref_reloc_sym;
+}
+
+static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc)
+{
+	struct ref_reloc_sym *reloc_sym;
+	struct symbol *sym;
+	struct map *map;
+
+	/* ref_reloc_sym is just a label. Need a special fix*/
+	reloc_sym = kernel_get_ref_reloc_sym();
+	if (reloc_sym && strcmp(name, reloc_sym->name) == 0)
+		return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr;
+	else {
+		sym = __find_kernel_function_by_name(name, &map);
+		if (sym)
+			return map->unmap_ip(map, sym->start) -
+				(reloc) ? 0 : map->reloc;
+	}
+	return 0;
+}
+
 static struct map *kernel_get_module_map(const char *module)
 {
 	struct rb_node *nd;
@@ -216,12 +252,26 @@ out:
 static int convert_to_perf_probe_point(struct probe_trace_point *tp,
 					struct perf_probe_point *pp)
 {
-	pp->function = strdup(tp->symbol);
+	struct symbol *sym;
+	struct map *map;
+	u64 addr = kernel_get_symbol_address_by_name(tp->symbol, true);
+
+	if (addr) {
+		addr += tp->offset;
+		sym = __find_kernel_function(addr, &map);
+		if (!sym)
+			goto failed;
+		pp->function = strdup(sym->name);
+		pp->offset = addr - map->unmap_ip(map, sym->start);
+	} else {
+failed:
+		pp->function = strdup(tp->symbol);
+		pp->offset = tp->offset;
+	}
 
 	if (pp->function == NULL)
 		return -ENOMEM;
 
-	pp->offset = tp->offset;
 	pp->retprobe = tp->retprobe;
 
 	return 0;
@@ -248,18 +298,6 @@ static struct debuginfo *open_debuginfo(const char *module)
 	return debuginfo__new(path);
 }
 
-static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
-{
-	/* kmap->ref_reloc_sym should be set if host_machine is initialized */
-	struct kmap *kmap;
-
-	if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0)
-		return NULL;
-
-	kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
-	return kmap->ref_reloc_sym;
-}
-
 /*
  * Convert trace point to probe point with debuginfo
  * Currently only handles kprobes.
@@ -267,24 +305,13 @@ static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 					struct perf_probe_point *pp)
 {
-	struct symbol *sym;
-	struct ref_reloc_sym *reloc_sym;
-	struct map *map;
 	u64 addr = 0;
 	int ret = -ENOENT;
 	struct debuginfo *dinfo;
 
-	/* ref_reloc_sym is just a label. Need a special fix*/
-	reloc_sym = __kernel_get_ref_reloc_sym();
-	if (reloc_sym && strcmp(tp->symbol, reloc_sym->name) == 0)
-		addr = reloc_sym->unrelocated_addr + tp->offset;
-	else {
-		sym = __find_kernel_function_by_name(tp->symbol, &map);
-		if (sym)
-			addr = map->unmap_ip(map, sym->start + tp->offset) -
-				map->reloc;
-	}
+	addr = kernel_get_symbol_address_by_name(tp->symbol, false);
 	if (addr) {
+		addr += tp->offset;
 		pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
 			 tp->offset, addr);
 
@@ -420,7 +447,7 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs,
 	if (module)
 		return add_module_to_probe_trace_events(tevs, ntevs, module);
 
-	reloc_sym = __kernel_get_ref_reloc_sym();
+	reloc_sym = kernel_get_ref_reloc_sym();
 	if (!reloc_sym) {
 		pr_warning("Relocated base symbol is not found!\n");
 		return -EINVAL;



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

* [PATCH -tip v3 09/11] perf-probe: Show source-level or symbol-level info for uprobes
  2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
                   ` (7 preceding siblings ...)
  2014-02-06  5:32 ` [PATCH -tip v3 08/11] perf-probe: Show appropriate symbol for ref_reloc_sym based kprobes Masami Hiramatsu
@ 2014-02-06  5:32 ` Masami Hiramatsu
  2014-02-22 18:01   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 10/11] perf-probe: Allow to add events on the local functions Masami Hiramatsu
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-06  5:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Show source-level or symbol-level information for uprobe events.

Without this change;
  # ./perf probe -l
    probe_perf:dso__load_vmlinux (on 0x000000000006d110 in /kbuild/ksrc/linux-3/tools/perf/perf)

With this change;
  # ./perf probe -l
    probe_perf:dso__load_vmlinux (on dso__load_vmlinux@util/symbol.c in /kbuild/ksrc/linux-3/tools/perf/perf)

Changes from v2:
 - Update according to previous patches.

Changes from v1:
 - Rewrite the code based on new series.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/probe-event.c |  227 ++++++++++++++++++++++++++---------------
 1 file changed, 144 insertions(+), 83 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f86820c..3c35b7a 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -249,34 +249,6 @@ out:
 	return ret;
 }
 
-static int convert_to_perf_probe_point(struct probe_trace_point *tp,
-					struct perf_probe_point *pp)
-{
-	struct symbol *sym;
-	struct map *map;
-	u64 addr = kernel_get_symbol_address_by_name(tp->symbol, true);
-
-	if (addr) {
-		addr += tp->offset;
-		sym = __find_kernel_function(addr, &map);
-		if (!sym)
-			goto failed;
-		pp->function = strdup(sym->name);
-		pp->offset = addr - map->unmap_ip(map, sym->start);
-	} else {
-failed:
-		pp->function = strdup(tp->symbol);
-		pp->offset = tp->offset;
-	}
-
-	if (pp->function == NULL)
-		return -ENOMEM;
-
-	pp->retprobe = tp->retprobe;
-
-	return 0;
-}
-
 #ifdef HAVE_DWARF_SUPPORT
 /* Open new debuginfo of given module */
 static struct debuginfo *open_debuginfo(const char *module)
@@ -298,44 +270,6 @@ static struct debuginfo *open_debuginfo(const char *module)
 	return debuginfo__new(path);
 }
 
-/*
- * Convert trace point to probe point with debuginfo
- * Currently only handles kprobes.
- */
-static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-					struct perf_probe_point *pp)
-{
-	u64 addr = 0;
-	int ret = -ENOENT;
-	struct debuginfo *dinfo;
-
-	addr = kernel_get_symbol_address_by_name(tp->symbol, false);
-	if (addr) {
-		addr += tp->offset;
-		pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
-			 tp->offset, addr);
-
-		dinfo = open_debuginfo(tp->module);
-		if (dinfo) {
-			ret = debuginfo__find_probe_point(dinfo,
-						 (unsigned long)addr, pp);
-			debuginfo__delete(dinfo);
-		} else {
-			pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n",
-				 addr);
-			ret = -ENOENT;
-		}
-	}
-	if (ret <= 0) {
-		pr_debug("Failed to find corresponding probes from "
-			 "debuginfo. Use kprobe event information.\n");
-		return convert_to_perf_probe_point(tp, pp);
-	}
-	pp->retprobe = tp->retprobe;
-
-	return 0;
-}
-
 static int get_text_start_address(const char *exec, unsigned long *address)
 {
 	Elf *elf;
@@ -364,6 +298,57 @@ out:
 	return ret;
 }
 
+/*
+ * Convert trace point to probe point with debuginfo
+ */
+static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
+					    struct perf_probe_point *pp,
+					    bool is_kprobe)
+{
+	struct debuginfo *dinfo = NULL;
+	unsigned long stext = 0;
+	u64 addr = tp->address;
+	int ret = -ENOENT;
+
+	/* convert the address to dwarf address */
+	if (!is_kprobe) {
+		if (!addr) {
+			ret = -EINVAL;
+			goto error;
+		}
+		ret = get_text_start_address(tp->module, &stext);
+		if (ret < 0)
+			goto error;
+		addr += stext;
+	} else {
+		addr = kernel_get_symbol_address_by_name(tp->symbol, false);
+		if (addr == 0)
+			goto error;
+		addr += tp->offset;
+	}
+
+	pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
+		 tp->module ? : "kernel");
+
+	dinfo = open_debuginfo(tp->module);
+	if (dinfo) {
+		ret = debuginfo__find_probe_point(dinfo,
+						 (unsigned long)addr, pp);
+		debuginfo__delete(dinfo);
+	} else {
+		pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr);
+		ret = -ENOENT;
+	}
+
+	if (ret > 0) {
+		pp->retprobe = tp->retprobe;
+		return 0;
+	}
+error:
+	pr_debug("Failed to find corresponding probes from debuginfo.\n");
+	return ret ? : -ENOENT;
+}
+
 static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
 					  int ntevs, const char *exec)
 {
@@ -815,10 +800,12 @@ out:
 
 #else	/* !HAVE_DWARF_SUPPORT */
 
-static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-					struct perf_probe_point *pp)
+static int
+find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused,
+				 struct perf_probe_point *pp __maybe_unused,
+				 bool is_kprobe __maybe_unused)
 {
-	return convert_to_perf_probe_point(tp, pp);
+	return -ENOSYS;
 }
 
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
@@ -1343,16 +1330,21 @@ static int parse_probe_trace_command(const char *cmd,
 	} else
 		p = argv[1];
 	fmt1_str = strtok_r(p, "+", &fmt);
-	tp->symbol = strdup(fmt1_str);
-	if (tp->symbol == NULL) {
-		ret = -ENOMEM;
-		goto out;
+	if (fmt1_str[0] == '0')	/* only the address started with 0x */
+		tp->address = strtoul(fmt1_str, NULL, 0);
+	else {
+		/* Only the symbol-based probe has offset */
+		tp->symbol = strdup(fmt1_str);
+		if (tp->symbol == NULL) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		fmt2_str = strtok_r(NULL, "", &fmt);
+		if (fmt2_str == NULL)
+			tp->offset = 0;
+		else
+			tp->offset = strtoul(fmt2_str, NULL, 10);
 	}
-	fmt2_str = strtok_r(NULL, "", &fmt);
-	if (fmt2_str == NULL)
-		tp->offset = 0;
-	else
-		tp->offset = strtoul(fmt2_str, NULL, 10);
 
 	tev->nargs = argc - 2;
 	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
@@ -1623,6 +1615,79 @@ error:
 	return NULL;
 }
 
+static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
+					  struct perf_probe_point *pp,
+					  bool is_kprobe)
+{
+	struct symbol *sym = NULL;
+	struct map *map;
+	u64 addr;
+	int ret = -ENOENT;
+
+	if (!is_kprobe) {
+		map = dso__new_map(tp->module);
+		if (!map)
+			goto out;
+		addr = tp->address;
+		sym = map__find_symbol(map, addr, NULL);
+	} else {
+		addr = kernel_get_symbol_address_by_name(tp->symbol, true);
+		if (addr) {
+			addr += tp->offset;
+			sym = __find_kernel_function(addr, &map);
+		}
+	}
+	if (!sym)
+		goto out;
+
+	pp->retprobe = tp->retprobe;
+	pp->offset = addr - map->unmap_ip(map, sym->start);
+	pp->function = strdup(sym->name);
+	ret = pp->function ? 0 : -ENOMEM;
+
+out:
+	if (map && !is_kprobe) {
+		dso__delete(map->dso);
+		map__delete(map);
+	}
+
+	return ret;
+}
+
+static int convert_to_perf_probe_point(struct probe_trace_point *tp,
+					struct perf_probe_point *pp,
+					bool is_kprobe)
+{
+	char buf[128];
+	int ret;
+
+	ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe);
+	if (!ret)
+		return 0;
+	ret = find_perf_probe_point_from_map(tp, pp, is_kprobe);
+	if (!ret)
+		return 0;
+
+	pr_debug("Failed to find probe point from both of dwarf and map.\n");
+
+	if (tp->symbol) {
+		pp->function = strdup(tp->symbol);
+		pp->offset = tp->offset;
+	} else if (!tp->module && !is_kprobe) {
+		ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address);
+		if (ret < 0)
+			return ret;
+		pp->function = strdup(buf);
+		pp->offset = 0;
+	}
+	if (pp->function == NULL)
+		return -ENOMEM;
+
+	pp->retprobe = tp->retprobe;
+
+	return 0;
+}
+
 static int convert_to_perf_probe_event(struct probe_trace_event *tev,
 			       struct perf_probe_event *pev, bool is_kprobe)
 {
@@ -1636,11 +1701,7 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
 		return -ENOMEM;
 
 	/* Convert trace_point to probe_point */
-	if (is_kprobe)
-		ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
-	else
-		ret = convert_to_perf_probe_point(&tev->point, &pev->point);
-
+	ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe);
 	if (ret < 0)
 		return ret;
 



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

* [PATCH -tip v3 10/11] perf-probe: Allow to add events on the local functions
  2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
                   ` (8 preceding siblings ...)
  2014-02-06  5:32 ` [PATCH -tip v3 09/11] perf-probe: Show source-level or symbol-level info for uprobes Masami Hiramatsu
@ 2014-02-06  5:32 ` Masami Hiramatsu
  2014-02-22 18:01   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
  2014-02-06  5:32 ` [PATCH -tip v3 11/11] perf probe: Support distro-style debuginfo for uprobe Masami Hiramatsu
  2014-02-14  5:43 ` [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
  11 siblings, 1 reply; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-06  5:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Allow to add events on the local functions without debuginfo.
(With the debuginfo, we can add events even on inlined functions)
Currently, probing on local functions requires debuginfo to
locate actual address. It is also possible without debuginfo since
we have symbol maps.

Without this change;
  ----
  # ./perf probe -a t_show
  Added new event:
    probe:t_show         (on t_show)

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

          perf record -e probe:t_show -aR sleep 1

  # ./perf probe -x perf -a identity__map_ip
  no symbols found in /kbuild/ksrc/linux-3/tools/perf/perf, maybe install a debug package?
  Failed to load map.
    Error: Failed to add events. (-22)
  ----
As the above results, perf probe just put one event
on the first found symbol for kprobe event. Moreover,
for uprobe event, perf probe failed to find local
functions.

With this change;
  ----
  # ./perf probe -a t_show
  Added new events:
    probe:t_show         (on t_show)
    probe:t_show_1       (on t_show)
    probe:t_show_2       (on t_show)
    probe:t_show_3       (on t_show)

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

          perf record -e probe:t_show_3 -aR sleep 1

  # ./perf probe -x perf -a identity__map_ip
  Added new events:
    probe_perf:identity__map_ip (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
    probe_perf:identity__map_ip_1 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
    probe_perf:identity__map_ip_2 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
    probe_perf:identity__map_ip_3 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)

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

          perf record -e probe_perf:identity__map_ip_3 -aR sleep 1
  ----
Now we succeed to put events on every given local functions
for both kprobes and uprobes. :)

Note that this also introduces some symbol rbtree
iteration macros; symbols__for_each, dso__for_each_symbol,
and map__for_each_symbol. These are for walking through
the symbol list in a map.

Changes from v2:
  - Fix add_exec_to_probe_trace_events() not to convert address
    to tp->symbol any more.
  - Fix to set kernel probes based on ref_reloc_sym.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/dso.h         |   10 +
 tools/perf/util/map.h         |   10 +
 tools/perf/util/probe-event.c |  378 +++++++++++++++++++----------------------
 tools/perf/util/symbol.h      |   11 +
 4 files changed, 204 insertions(+), 205 deletions(-)

diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index cd7d6f0..ab06f1c 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -102,6 +102,16 @@ struct dso {
 	char		 name[0];
 };
 
+/* dso__for_each_symbol - iterate over the symbols of given type
+ *
+ * @dso: the 'struct dso *' in which symbols itereated
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @n: the 'struct rb_node *' to use as a temporary storage
+ * @type: the 'enum map_type' type of symbols
+ */
+#define dso__for_each_symbol(dso, pos, n, type)	\
+	symbols__for_each_entry(&(dso)->symbols[(type)], pos, n)
+
 static inline void dso__set_loaded(struct dso *dso, enum map_type type)
 {
 	dso->loaded |= (1 << type);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 257e513..f00f058 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -90,6 +90,16 @@ u64 map__objdump_2mem(struct map *map, u64 ip);
 
 struct symbol;
 
+/* map__for_each_symbol - iterate over the symbols in the given map
+ *
+ * @map: the 'struct map *' in which symbols itereated
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @n: the 'struct rb_node *' to use as a temporary storage
+ * Note: caller must ensure map->dso is not NULL (map is loaded).
+ */
+#define map__for_each_symbol(map, pos, n)	\
+	dso__for_each_symbol(map->dso, pos, n, map->type)
+
 typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
 
 void map__init(struct map *map, enum map_type type,
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 3c35b7a..42bec67 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -70,8 +70,6 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 }
 
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
-static int convert_name_to_addr(struct perf_probe_event *pev,
-				const char *exec);
 static void clear_probe_trace_event(struct probe_trace_event *tev);
 static struct machine *host_machine;
 
@@ -249,6 +247,14 @@ out:
 	return ret;
 }
 
+static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
+{
+	int i;
+
+	for (i = 0; i < ntevs; i++)
+		clear_probe_trace_event(tevs + i);
+}
+
 #ifdef HAVE_DWARF_SUPPORT
 /* Open new debuginfo of given module */
 static struct debuginfo *open_debuginfo(const char *module)
@@ -353,8 +359,7 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
 					  int ntevs, const char *exec)
 {
 	int i, ret = 0;
-	unsigned long offset, stext = 0;
-	char buf[32];
+	unsigned long stext = 0;
 
 	if (!exec)
 		return 0;
@@ -365,15 +370,9 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
 
 	for (i = 0; i < ntevs && ret >= 0; i++) {
 		/* point.address is the addres of point.symbol + point.offset */
-		offset = tevs[i].point.address - stext;
-		tevs[i].point.offset = 0;
-		zfree(&tevs[i].point.symbol);
-		ret = e_snprintf(buf, 32, "0x%lx", offset);
-		if (ret < 0)
-			break;
+		tevs[i].point.address -= stext;
 		tevs[i].point.module = strdup(exec);
-		tevs[i].point.symbol = strdup(buf);
-		if (!tevs[i].point.symbol || !tevs[i].point.module) {
+		if (!tevs[i].point.module) {
 			ret = -ENOMEM;
 			break;
 		}
@@ -452,14 +451,6 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs,
 	return 0;
 }
 
-static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
-{
-	int i;
-
-	for (i = 0; i < ntevs; i++)
-		clear_probe_trace_event(tevs + i);
-}
-
 /* 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,
@@ -1586,20 +1577,27 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
 	if (buf == NULL)
 		return NULL;
 
+	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
+			 tev->group, tev->event);
+	if (len <= 0)
+		goto error;
+
+	/* Uprobes must have tp->address and tp->module */
+	if (tev->uprobes && (!tp->address || !tp->module))
+		goto error;
+
+	/* Use the tp->address for uprobes */
 	if (tev->uprobes)
-		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
-				 tp->retprobe ? 'r' : 'p',
-				 tev->group, tev->event,
-				 tp->module, tp->symbol);
+		ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx",
+				 tp->module, tp->address);
 	else
-		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
-				 tp->retprobe ? 'r' : 'p',
-				 tev->group, tev->event,
+		ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu",
 				 tp->module ?: "", tp->module ? ":" : "",
 				 tp->symbol, tp->offset);
 
-	if (len <= 0)
+	if (ret <= 0)
 		goto error;
+	len += ret;
 
 	for (i = 0; i < tev->nargs; i++) {
 		ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
@@ -2150,113 +2148,175 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 	return ret;
 }
 
-static int convert_to_probe_trace_events(struct perf_probe_event *pev,
-					  struct probe_trace_event **tevs,
-					  int max_tevs, const char *target)
+static char *looking_function_name;
+static int num_matched_functions;
+
+static int probe_function_filter(struct map *map __maybe_unused,
+				      struct symbol *sym)
+{
+	if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
+	    strcmp(looking_function_name, sym->name) == 0) {
+		num_matched_functions++;
+		return 0;
+	}
+	return 1;
+}
+
+#define strdup_or_goto(str, label)	\
+	({ char *__p = strdup(str); if (!__p) goto label; __p; })
+
+/*
+ * Find probe function addresses from map.
+ * Return an error or the number of found probe_trace_event
+ */
+static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
+					    struct probe_trace_event **tevs,
+					    int max_tevs, const char *target)
 {
+	struct map *map = NULL;
+	struct kmap *kmap = NULL;
+	struct ref_reloc_sym *reloc_sym = NULL;
 	struct symbol *sym;
-	int ret, i;
+	struct rb_node *nd;
 	struct probe_trace_event *tev;
+	struct perf_probe_point *pp = &pev->point;
+	struct probe_trace_point *tp;
+	int ret, i;
 
-	if (pev->uprobes && !pev->group) {
-		/* Replace group name if not given */
-		ret = convert_exec_to_group(target, &pev->group);
-		if (ret != 0) {
-			pr_warning("Failed to make a group name.\n");
-			return ret;
-		}
+	/* Init maps of given executable or kernel */
+	if (pev->uprobes)
+		map = dso__new_map(target);
+	else
+		map = kernel_get_module_map(target);
+	if (!map) {
+		ret = -EINVAL;
+		goto out;
 	}
 
-	/* Convert perf_probe_event with debuginfo */
-	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
-	if (ret != 0)
-		return ret;	/* Found in debuginfo or got an error */
-
-	if (pev->uprobes) {
-		ret = convert_name_to_addr(pev, target);
-		if (ret < 0)
-			return ret;
+	/*
+	 * Load matched symbols: Since the different local symbols may have
+	 * same name but different addresses, this lists all the symbols.
+	 */
+	num_matched_functions = 0;
+	looking_function_name = pp->function;
+	ret = map__load(map, probe_function_filter);
+	if (ret || num_matched_functions == 0) {
+		pr_err("Failed to find symbol %s in %s\n", pp->function,
+			target ? : "kernel");
+		ret = -ENOENT;
+		goto out;
+	} else if (num_matched_functions > max_tevs) {
+		pr_err("Too many functions matched in %s\n",
+			target ? : "kernel");
+		ret = -E2BIG;
+		goto out;
 	}
 
-	/* Allocate trace event buffer */
-	tev = *tevs = zalloc(sizeof(struct probe_trace_event));
-	if (tev == NULL)
-		return -ENOMEM;
+	if (!pev->uprobes) {
+		kmap = map__kmap(map);
+		reloc_sym = kmap->ref_reloc_sym;
+		if (!reloc_sym) {
+			pr_warning("Relocated base symbol is not found!\n");
+			ret = -EINVAL;
+			goto out;
+		}
+	}
 
-	/* Copy parameters */
-	tev->point.symbol = strdup(pev->point.function);
-	if (tev->point.symbol == NULL) {
+	/* Setup result trace-probe-events */
+	*tevs = zalloc(sizeof(*tev) * num_matched_functions);
+	if (!*tevs) {
 		ret = -ENOMEM;
-		goto error;
+		goto out;
 	}
 
-	if (target) {
-		tev->point.module = strdup(target);
-		if (tev->point.module == NULL) {
-			ret = -ENOMEM;
-			goto error;
+	ret = 0;
+	map__for_each_symbol(map, sym, nd) {
+		tev = (*tevs) + ret;
+		tp = &tev->point;
+		if (ret == num_matched_functions) {
+			pr_warning("Too many symbols are listed. Skip it.\n");
+			break;
 		}
-	}
+		ret++;
 
-	tev->point.offset = pev->point.offset;
-	tev->point.retprobe = pev->point.retprobe;
-	tev->nargs = pev->nargs;
-	tev->uprobes = pev->uprobes;
-
-	if (tev->nargs) {
-		tev->args = zalloc(sizeof(struct probe_trace_arg)
-				   * tev->nargs);
-		if (tev->args == NULL) {
-			ret = -ENOMEM;
-			goto error;
+		if (pp->offset > sym->end - sym->start) {
+			pr_warning("Offset %ld is bigger than the size of %s\n",
+				   pp->offset, sym->name);
+			ret = -ENOENT;
+			goto err_out;
+		}
+		/* Add one probe point */
+		tp->address = map->unmap_ip(map, sym->start) + pp->offset;
+		if (reloc_sym) {
+			tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out);
+			tp->offset = tp->address - reloc_sym->addr;
+		} else {
+			tp->symbol = strdup_or_goto(sym->name, nomem_out);
+			tp->offset = pp->offset;
+		}
+		tp->retprobe = pp->retprobe;
+		if (target)
+			tev->point.module = strdup_or_goto(target, nomem_out);
+		tev->uprobes = pev->uprobes;
+		tev->nargs = pev->nargs;
+		if (tev->nargs) {
+			tev->args = zalloc(sizeof(struct probe_trace_arg) *
+					   tev->nargs);
+			if (tev->args == NULL)
+				goto nomem_out;
 		}
 		for (i = 0; i < tev->nargs; i++) {
-			if (pev->args[i].name) {
-				tev->args[i].name = strdup(pev->args[i].name);
-				if (tev->args[i].name == NULL) {
-					ret = -ENOMEM;
-					goto error;
-				}
-			}
-			tev->args[i].value = strdup(pev->args[i].var);
-			if (tev->args[i].value == NULL) {
-				ret = -ENOMEM;
-				goto error;
-			}
-			if (pev->args[i].type) {
-				tev->args[i].type = strdup(pev->args[i].type);
-				if (tev->args[i].type == NULL) {
-					ret = -ENOMEM;
-					goto error;
-				}
-			}
+			if (pev->args[i].name)
+				tev->args[i].name =
+					strdup_or_goto(pev->args[i].name,
+							nomem_out);
+
+			tev->args[i].value = strdup_or_goto(pev->args[i].var,
+							    nomem_out);
+			if (pev->args[i].type)
+				tev->args[i].type =
+					strdup_or_goto(pev->args[i].type,
+							nomem_out);
 		}
 	}
 
-	if (pev->uprobes)
-		return 1;
+out:
+	if (map && pev->uprobes) {
+		/* Only when using uprobe(exec) map needs to be released */
+		dso__delete(map->dso);
+		map__delete(map);
+	}
+	return ret;
 
-	/* Currently just checking function name from symbol map */
-	sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
-	if (!sym) {
-		pr_warning("Kernel symbol \'%s\' not found.\n",
-			   tev->point.symbol);
-		ret = -ENOENT;
-		goto error;
-	} else if (tev->point.offset > sym->end - sym->start) {
-		pr_warning("Offset specified is greater than size of %s\n",
-			   tev->point.symbol);
-		ret = -ENOENT;
-		goto error;
+nomem_out:
+	ret = -ENOMEM;
+err_out:
+	clear_probe_trace_events(*tevs, num_matched_functions);
+	zfree(tevs);
+	goto out;
+}
 
+static int convert_to_probe_trace_events(struct perf_probe_event *pev,
+					  struct probe_trace_event **tevs,
+					  int max_tevs, const char *target)
+{
+	int ret;
+
+	if (pev->uprobes && !pev->group) {
+		/* Replace group name if not given */
+		ret = convert_exec_to_group(target, &pev->group);
+		if (ret != 0) {
+			pr_warning("Failed to make a group name.\n");
+			return ret;
+		}
 	}
 
-	return 1;
-error:
-	clear_probe_trace_event(tev);
-	free(tev);
-	*tevs = NULL;
-	return ret;
+	/* Convert perf_probe_event with debuginfo */
+	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
+	if (ret != 0)
+		return ret;	/* Found in debuginfo or got an error */
+
+	return find_probe_trace_events_from_map(pev, tevs, max_tevs, target);
 }
 
 struct __event_package {
@@ -2461,7 +2521,7 @@ static struct strfilter *available_func_filter;
 static int filter_available_functions(struct map *map __maybe_unused,
 				      struct symbol *sym)
 {
-	if (sym->binding == STB_GLOBAL &&
+	if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
 	    strfilter__compare(available_func_filter, sym->name))
 		return 0;
 	return 1;
@@ -2509,95 +2569,3 @@ end:
 	return ret;
 }
 
-/*
- * uprobe_events only accepts address:
- * Convert function and any offset to address
- */
-static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
-{
-	struct perf_probe_point *pp = &pev->point;
-	struct symbol *sym;
-	struct map *map = NULL;
-	char *function = NULL;
-	int ret = -EINVAL;
-	unsigned long long vaddr = 0;
-
-	if (!pp->function) {
-		pr_warning("No function specified for uprobes");
-		goto out;
-	}
-
-	function = strdup(pp->function);
-	if (!function) {
-		pr_warning("Failed to allocate memory by strdup.\n");
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	map = dso__new_map(exec);
-	if (!map) {
-		pr_warning("Cannot find appropriate DSO for %s.\n", exec);
-		goto out;
-	}
-	available_func_filter = strfilter__new(function, NULL);
-	if (map__load(map, filter_available_functions)) {
-		pr_err("Failed to load map.\n");
-		goto out;
-	}
-
-	sym = map__find_symbol_by_name(map, function, NULL);
-	if (!sym) {
-		pr_warning("Cannot find %s in DSO %s\n", function, exec);
-		goto out;
-	}
-
-	if (map->start > sym->start)
-		vaddr = map->start;
-	vaddr += sym->start + pp->offset + map->pgoff;
-	pp->offset = 0;
-
-	if (!pev->event) {
-		pev->event = function;
-		function = NULL;
-	}
-	if (!pev->group) {
-		char *ptr1, *ptr2, *exec_copy;
-
-		pev->group = zalloc(sizeof(char *) * 64);
-		exec_copy = strdup(exec);
-		if (!exec_copy) {
-			ret = -ENOMEM;
-			pr_warning("Failed to copy exec string.\n");
-			goto out;
-		}
-
-		ptr1 = strdup(basename(exec_copy));
-		if (ptr1) {
-			ptr2 = strpbrk(ptr1, "-._");
-			if (ptr2)
-				*ptr2 = '\0';
-			e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
-					ptr1);
-			free(ptr1);
-		}
-		free(exec_copy);
-	}
-	free(pp->function);
-	pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
-	if (!pp->function) {
-		ret = -ENOMEM;
-		pr_warning("Failed to allocate memory by zalloc.\n");
-		goto out;
-	}
-	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
-	ret = 0;
-
-out:
-	if (map) {
-		dso__delete(map->dso);
-		map__delete(map);
-	}
-	if (function)
-		free(function);
-	return ret;
-}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index fffe288..9c4fc23 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -79,6 +79,17 @@ struct symbol {
 void symbol__delete(struct symbol *sym);
 void symbols__delete(struct rb_root *symbols);
 
+/* symbols__for_each_entry - iterate over symbols (rb_root)
+ *
+ * @symbols: the rb_root of symbols
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @nd: the 'struct rb_node *' to use as a temporary storage
+ */
+#define symbols__for_each_entry(symbols, pos, nd)			\
+	for (nd = rb_first(symbols);					\
+	     nd && (pos = rb_entry(nd, struct symbol, rb_node));	\
+	     nd = rb_next(nd))
+
 static inline size_t symbol__size(const struct symbol *sym)
 {
 	return sym->end - sym->start + 1;



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

* [PATCH -tip v3 11/11] perf probe: Support distro-style debuginfo for uprobe
  2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
                   ` (9 preceding siblings ...)
  2014-02-06  5:32 ` [PATCH -tip v3 10/11] perf-probe: Allow to add events on the local functions Masami Hiramatsu
@ 2014-02-06  5:32 ` Masami Hiramatsu
  2014-02-22 18:01   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
  2014-02-14  5:43 ` [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
  11 siblings, 1 reply; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-06  5:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Support distro-style debuginfo supported by dso for setting
uprobes. Note that this tries to find a debuginfo file based
on the real path of the target binary. If the debuginfo is
not correctly installed on the system, this can not find it.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
---
 tools/perf/util/probe-event.c  |    9 +++------
 tools/perf/util/probe-finder.c |   41 ++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/probe-finder.h |    1 +
 3 files changed, 43 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 42bec67..0d1542f 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -256,17 +256,14 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
 }
 
 #ifdef HAVE_DWARF_SUPPORT
+
 /* Open new debuginfo of given module */
 static struct debuginfo *open_debuginfo(const char *module)
 {
-	const char *path;
+	const char *path = module;
 
-	/* A file path -- this is an offline module */
-	if (module && strchr(module, '/'))
-		path = module;
-	else {
+	if (!module || !strchr(module, '/')) {
 		path = kernel_get_module_path(module);
-
 		if (!path) {
 			pr_err("Failed to find path of %s module.\n",
 			       module ?: "kernel");
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4f6e277..df02386 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -34,6 +34,7 @@
 
 #include <linux/bitops.h>
 #include "event.h"
+#include "dso.h"
 #include "debug.h"
 #include "intlist.h"
 #include "util.h"
@@ -89,7 +90,7 @@ error:
 	return -ENOENT;
 }
 
-struct debuginfo *debuginfo__new(const char *path)
+static struct debuginfo *__debuginfo__new(const char *path)
 {
 	struct debuginfo *dbg = zalloc(sizeof(*dbg));
 	if (!dbg)
@@ -97,10 +98,46 @@ struct debuginfo *debuginfo__new(const char *path)
 
 	if (debuginfo__init_offline_dwarf(dbg, path) < 0)
 		zfree(&dbg);
-
+	if (dbg)
+		pr_debug("Open Debuginfo file: %s\n", path);
 	return dbg;
 }
 
+enum dso_binary_type distro_dwarf_types[] = {
+	DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
+	DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
+	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
+	DSO_BINARY_TYPE__NOT_FOUND,
+};
+
+struct debuginfo *debuginfo__new(const char *path)
+{
+	enum dso_binary_type *type;
+	char buf[PATH_MAX], nil = '\0';
+	struct dso *dso;
+	struct debuginfo *dinfo = NULL;
+
+	/* Try to open distro debuginfo files */
+	dso = dso__new(path);
+	if (!dso)
+		goto out;
+
+	for (type = distro_dwarf_types;
+	     !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;
+	     type++) {
+		if (dso__read_binary_type_filename(dso, *type, &nil,
+						   buf, PATH_MAX) < 0)
+			continue;
+		dinfo = __debuginfo__new(buf);
+	}
+	dso__delete(dso);
+
+out:
+	/* if failed to open all distro debuginfo, open given binary */
+	return dinfo ? : __debuginfo__new(path);
+}
+
 void debuginfo__delete(struct debuginfo *dbg)
 {
 	if (dbg) {
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 3fc5973..92590b2 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -30,6 +30,7 @@ struct debuginfo {
 	Dwarf_Addr	bias;
 };
 
+/* This also tries to open distro debuginfo */
 extern struct debuginfo *debuginfo__new(const char *path);
 extern void debuginfo__delete(struct debuginfo *dbg);
 



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

* Re: [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo
  2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
                   ` (10 preceding siblings ...)
  2014-02-06  5:32 ` [PATCH -tip v3 11/11] perf probe: Support distro-style debuginfo for uprobe Masami Hiramatsu
@ 2014-02-14  5:43 ` Masami Hiramatsu
  2014-02-17 18:28   ` Arnaldo Carvalho de Melo
  11 siblings, 1 reply; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-14  5:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Ping? :)

(2014/02/06 14:32), Masami Hiramatsu wrote:
> Hi,
> 
> Here is the 3rd version of the series for handling local
> functions correctly with perf-probe. This version also
> includes distro debuginfo-file support (a small
> enhancement, based on existing feature).
> 
> In this version, I used ref_reloc_sym based probe point
> instead of absolute address/"_stext", because kASLR
> changes the address offset randomly and the debuginfo
> doesn't know that offset. Recently perftools supports
> kASLR by introducing ref_reloc_sym (which is usually
> "_text" or "_stext"). Since we already ensured that
> the kmap->ref_reloc_sym symbol exists in the kernel,
> it is safe to reuse it for the reference point of
> probe points.
> 
> Note that this series requires a bugfix patch:
>   perf-probe: Do not add offset to uprobe address
>   https://lkml.org/lkml/2014/2/5/7
> 
> 
> Issue 1)
>  Current perf-probe can't handle probe-points for kprobes,
>  since it uses symbol-based probe definition. The symbol
>  based definition is easy to read and robust for differnt
>  kernel and modules. However, when user gives a local
>  function name which has several different instances,
>  it may put probes on wrong (or unexpected) address.
>  On the other hand, since uprobe events are based on the
>  actual address, it can avoid this issue.
> 
>  E.g.
> In the case to probe t_show local functions (which has
> 4 different instances.
>   ----
>   # grep " t_show\$" /proc/kallsyms
>   ffffffff810d9720 t t_show
>   ffffffff810e2e40 t t_show
>   ffffffff810ece30 t t_show
>   ffffffff810f4ad0 t t_show
>   # ./perf probe -fa "t_show \$vars"
>   Added new events:
>     probe:t_show         (on t_show with $vars)
>     probe:t_show_1       (on t_show with $vars)
>     probe:t_show_2       (on t_show with $vars)
>     probe:t_show_3       (on t_show with $vars)
> 
>   You can now use it in all perf tools, such as:
> 
>           perf record -e probe:t_show_3 -aR sleep 1
>   ----
> OK, we have 4 different t_show()s. All functions have
> different arguments as below;
>   ----
>   # cat /sys/kernel/debug/tracing/kprobe_events
>   p:probe/t_show t_show m=%di:u64 v=%si:u64
>   p:probe/t_show_1 t_show m=%di:u64 v=%si:u64 t=%si:u64
>   p:probe/t_show_2 t_show m=%di:u64 v=%si:u64 fmt=%si:u64
>   p:probe/t_show_3 t_show m=%di:u64 v=%si:u64 file=%si:u64
>   ----
> However, all of them have been put on the *same* address.
>   ----
>   # cat /sys/kernel/debug/kprobes/list
>   ffffffff810d9720  k  t_show+0x0    [DISABLED]
>   ffffffff810d9720  k  t_show+0x0    [DISABLED]
>   ffffffff810d9720  k  t_show+0x0    [DISABLED]
>   ffffffff810d9720  k  t_show+0x0    [DISABLED]
>   ----
>  oops...
> 
> Issue 2)
>  With the debuginfo, issue 1 can be solved by using
>  _stext-based probe definition instead of local symbol-based.
>  However, without debuginfo, perf-probe can only use
>  symbol-map in the binary (or kallsyms). The map provides
>  symbol find methods, but it returns only the first matched
>  symbol. To put probes on all functions which have given
>  symbol, we need a symbol-list iterator for the map.
> 
>  E.g. (built perf with NO_DWARF=1)
> In the case to probe t_show and identity__map_ip in perf.
>   ----
>   # ./perf probe -a t_show
>   Added new event:
>     probe:t_show         (on t_show)
> 
>   You can now use it in all perf tools, such as:
> 
>           perf record -e probe:t_show -aR sleep 1
> 
>   # ./perf probe -x perf -a identity__map_ip
>   no symbols found in /kbuild/ksrc/linux-3/tools/perf/perf, maybe install a debug package?
>   Failed to load map.
>     Error: Failed to add events. (-22)
>   ----
>  oops.....
> 
> 
> Solutions)
> To solve the issue 1, this series changes perf probe to
> use _stext-based probe definition. This means that we
> also need to fix the --list options to analyze actual
> probe address from _stext address. (and that has been
> done in this series).
> 
> E.g. with this series;
>   ----
>   # ./perf probe -a "t_show \$vars"
>   Added new events:
>     probe:t_show         (on t_show with $vars)
>     probe:t_show_1       (on t_show with $vars)
>     probe:t_show_2       (on t_show with $vars)
>     probe:t_show_3       (on t_show with $vars)
> 
>   You can now use it in all perf tools, such as:
> 
>           perf record -e probe:t_show_3 -aR sleep 1
> 
>   # cat /sys/kernel/debug/tracing/kprobe_events
>   p:probe/t_show _stext+889880 m=%di:u64 v=%si:u64
>   p:probe/t_show_1 _stext+928568 m=%di:u64 v=%si:u64 t=%si:u64
>   p:probe/t_show_2 _stext+969512 m=%di:u64 v=%si:u64 fmt=%si:u64
>   p:probe/t_show_3 _stext+1001416 m=%di:u64 v=%si:u64 file=%si:u64
> 
>   # cat /sys/kernel/debug/kprobes/list
>   ffffffffb50d95e0  k  t_show+0x0    [DISABLED]
>   ffffffffb50e2d00  k  t_show+0x0    [DISABLED]
>   ffffffffb50f4990  k  t_show+0x0    [DISABLED]
>   ffffffffb50eccf0  k  t_show+0x0    [DISABLED]
>   ----
> This time we can see the events are set in different
> addresses.
> 
> And for the issue 2, the last patch introduces symbol
> iterators for map, dso and symbols (since the symbol
> list is the symbols and it is included in dso, and perf
> probe accesses dso via map).
> 
> E.g. with this series (built perf with NO_DWARF=1);
>   ----
>   # ./perf probe -a t_show
>   Added new events:
>     probe:t_show         (on t_show)
>     probe:t_show_1       (on t_show)
>     probe:t_show_2       (on t_show)
>     probe:t_show_3       (on t_show)
> 
>   You can now use it in all perf tools, such as:
> 
>           perf record -e probe:t_show_3 -aR sleep 1
> 
>   # ./perf probe -x perf -a identity__map_ip
>   Added new events:
>     probe_perf:identity__map_ip (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
>     probe_perf:identity__map_ip_1 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
>     probe_perf:identity__map_ip_2 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
>     probe_perf:identity__map_ip_3 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
> 
>   You can now use it in all perf tools, such as:
> 
>           perf record -e probe_perf:identity__map_ip_3 -aR sleep 1
>   ----
> Now, even without the debuginfo, both the kprobe and
> uprobe are set 4 different places correctly.
> 
> BTW, while testing above, I've found some bugs and
> another minor issue; perf-probe doesn't show the
> modules and binaries in which probes are set.
> I've also fixed it in this series as below.
> 
> Without the fix;
> 
>   # ./perf probe -m drm drm_av_sync_delay
>   # ./perf probe -x perf dso__load_vmlinux
> 
>   # ./perf probe -l
>     probe:drm_av_sync_delay (on drm_av_sync_delay)
>     probe_perf:dso__load_vmlinux (on 0x000000000006d110)
> 
> With this fix;
> 
>   # ./perf probe -l
>     probe:drm_av_sync_delay (on drm_av_sync_delay in drm)
>     probe_perf:dso__load_vmlinux (on 0x000000000006d110 in /kbuild/ksrc/linux-3/tools/perf/perf)
> 
> Changes from v2:
>  - Use ref_reloc_sym instead of "_stext" for reference point.
>    (Thanks for Namhyung Kim!)
>  - Add 2 cleanup patches for reducing the redundant features.
>  - Add distro-style debuginfo support.
> 
> TODO:
>  - Support local functions in modules. This requires kernel
>  side enhancement to allow setting probes by the relative
>  addresses in modules too.
>  - Uprobe-event MUST traces the change of given binary even
>  when the event is disabled. I've found that user can replace
>  the target binary after setting events and the events can be
>  enabled on the different instructions...
> 
> ---
> 
> Masami Hiramatsu (11):
>       [BUGFIX] perf-probe: Fix to do exit call for symbol maps
>       [CLEANUP] perf-probe: Remove incorrect symbol check for --list
>       [CLEANUP] perf-probe: Replace line_list with intlist
>       [CLEANUP] perf-probe: Unify show_available_functions for uprobes/kprobes
>       perf-probe: Show in what binaries/modules probes are set
>       perf-probe: Use ref_reloc_sym based address instead of the symbol name
>       perf-probe: Find given address from offline dwarf
>       perf-probe: Show appropriate symbol for ref_reloc_sym based kprobes
>       perf-probe: Show source-level or symbol-level info for uprobes
>       perf-probe: Allow to add events on the local functions
>       perf probe: Support distro-style debuginfo for uprobe
> 
> 
>  tools/perf/builtin-probe.c     |   12 -
>  tools/perf/util/dso.h          |   10 
>  tools/perf/util/map.h          |   10 
>  tools/perf/util/probe-event.c  |  863 ++++++++++++++++++++++------------------
>  tools/perf/util/probe-event.h  |   12 -
>  tools/perf/util/probe-finder.c |  198 ++-------
>  tools/perf/util/probe-finder.h |    5 
>  tools/perf/util/symbol.h       |   11 +
>  8 files changed, 566 insertions(+), 555 deletions(-)
> 


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



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

* Re: [PATCH -tip v3 01/11] [BUGFIX] perf-probe: Fix to do exit call for symbol maps
  2014-02-06  5:32 ` [PATCH -tip v3 01/11] [BUGFIX] perf-probe: Fix to do exit call for symbol maps Masami Hiramatsu
@ 2014-02-17  7:56   ` Namhyung Kim
  2014-02-17 11:44     ` Masami Hiramatsu
  2014-02-22 17:59   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
  1 sibling, 1 reply; 29+ messages in thread
From: Namhyung Kim @ 2014-02-17  7:56 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Arnaldo Carvalho de Melo, Srikar Dronamraju, David Ahern,
	linux-kernel, Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt

Hi Masami,

On Thu, 06 Feb 2014 05:32:04 +0000, Masami Hiramatsu wrote:
> Some perf-probe commands do symbol_init() but doesn't
> do exit call. This fixes that to call symbol_exit()
> and releases machine if needed.
> This also merges init_vmlinux() and init_user_exec()
> because both of them are doing similar things.
> (init_user_exec() just skips init vmlinux related
>  symbol maps)
>
> Changes from v2:
>  - Not to set symbol_conf.try_vmlinux_path in init_symbol_maps()
>    (Thanks to Namhyung Kim!)
>
> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>

[SNIP]
> -int show_line_range(struct line_range *lr, const char *module)
> +static int __show_line_range(struct line_range *lr, const char *module)
>  {
>  	int l = 1;
>  	struct line_node *ln;
> @@ -573,10 +568,6 @@ int show_line_range(struct line_range *lr, const char *module)
>  	char *tmp;
>  
>  	/* Search a line range */
> -	ret = init_vmlinux();
> -	if (ret < 0)
> -		return ret;
> -
>  	dinfo = open_debuginfo(module);
>  	if (!dinfo) {
>  		pr_warning("Failed to open debuginfo file.\n");
> @@ -646,6 +637,19 @@ end:
>  	return ret;
>  }
>  
> +int show_line_range(struct line_range *lr, const char *module)
> +{
> +	int ret;
> +
> +	ret = init_symbol_maps(false);
> +	if (ret < 0)
> +		return ret;
> +	ret = __show_line_range(lr, module);
> +	exit_symbol_maps();

Wouldn't it be better moving init/exit_symbol_maps() to a common
location if they're used by every operations?

Thanks,
Namhyung

> +
> +	return ret;
> +}
> +
>  static int show_available_vars_at(struct debuginfo *dinfo,
>  				  struct perf_probe_event *pev,
>  				  int max_vls, struct strfilter *_filter,
> @@ -707,14 +711,15 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
>  	int i, ret = 0;
>  	struct debuginfo *dinfo;
>  
> -	ret = init_vmlinux();
> +	ret = init_symbol_maps(false);
>  	if (ret < 0)
>  		return ret;
>  
>  	dinfo = open_debuginfo(module);
>  	if (!dinfo) {
>  		pr_warning("Failed to open debuginfo file.\n");
> -		return -ENOENT;
> +		ret = -ENOENT;
> +		goto out;
>  	}
>  
>  	setup_pager();
> @@ -724,6 +729,8 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
>  					     externs);
>  
>  	debuginfo__delete(dinfo);
> +out:
> +	exit_symbol_maps();
>  	return ret;
>  }
>  
> @@ -1807,7 +1814,7 @@ int show_perf_probe_events(void)
>  	if (fd < 0)
>  		return fd;
>  
> -	ret = init_vmlinux();
> +	ret = init_symbol_maps(false);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -1820,6 +1827,7 @@ int show_perf_probe_events(void)
>  		close(fd);
>  	}
>  
> +	exit_symbol_maps();
>  	return ret;
>  }
>  
> @@ -2135,12 +2143,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
>  	if (pkgs == NULL)
>  		return -ENOMEM;
>  
> -	if (!pevs->uprobes)
> -		/* Init vmlinux path */
> -		ret = init_vmlinux();
> -	else
> -		ret = init_user_exec();
> -
> +	ret = init_symbol_maps(pevs->uprobes);
>  	if (ret < 0) {
>  		free(pkgs);
>  		return ret;
> @@ -2174,6 +2177,7 @@ end:
>  		zfree(&pkgs[i].tevs);
>  	}
>  	free(pkgs);
> +	exit_symbol_maps();
>  
>  	return ret;
>  }
> @@ -2347,7 +2351,7 @@ static int available_kernel_funcs(const char *module)
>  	struct map *map;
>  	int ret;
>  
> -	ret = init_vmlinux();
> +	ret = init_symbol_maps(false);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -2356,7 +2360,10 @@ static int available_kernel_funcs(const char *module)
>  		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
>  		return -EINVAL;
>  	}
> -	return __show_available_funcs(map);
> +	ret = __show_available_funcs(map);
> +	exit_symbol_maps();
> +
> +	return ret;
>  }
>  
>  static int available_user_funcs(const char *target)
> @@ -2364,7 +2371,7 @@ static int available_user_funcs(const char *target)
>  	struct map *map;
>  	int ret;
>  
> -	ret = init_user_exec();
> +	ret = init_symbol_maps(true);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -2372,6 +2379,7 @@ static int available_user_funcs(const char *target)
>  	ret = __show_available_funcs(map);
>  	dso__delete(map->dso);
>  	map__delete(map);
> +	exit_symbol_maps();
>  	return ret;
>  }
>  

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

* Re: [PATCH -tip v3 03/11] [CLEANUP] perf-probe: Replace line_list with intlist
  2014-02-06  5:32 ` [PATCH -tip v3 03/11] [CLEANUP] perf-probe: Replace line_list with intlist Masami Hiramatsu
@ 2014-02-17  7:58   ` Namhyung Kim
  2014-02-22 18:00   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
  1 sibling, 0 replies; 29+ messages in thread
From: Namhyung Kim @ 2014-02-17  7:58 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Arnaldo Carvalho de Melo, Srikar Dronamraju, David Ahern,
	linux-kernel, Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt

On Thu, 06 Feb 2014 05:32:09 +0000, Masami Hiramatsu wrote:
> Replace line_list (struct line_node) with intlist for
> reducing similar codes.

Acked-by: Namhyung Kim <namhyung@kernel.org>

Thanks,
Namhyung

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

* Re: [PATCH -tip v3 01/11] [BUGFIX] perf-probe: Fix to do exit call for symbol maps
  2014-02-17  7:56   ` Namhyung Kim
@ 2014-02-17 11:44     ` Masami Hiramatsu
  0 siblings, 0 replies; 29+ messages in thread
From: Masami Hiramatsu @ 2014-02-17 11:44 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, Srikar Dronamraju, David Ahern,
	linux-kernel, Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt

(2014/02/17 16:56), Namhyung Kim wrote:
> Hi Masami,
> 
> On Thu, 06 Feb 2014 05:32:04 +0000, Masami Hiramatsu wrote:
>> Some perf-probe commands do symbol_init() but doesn't
>> do exit call. This fixes that to call symbol_exit()
>> and releases machine if needed.
>> This also merges init_vmlinux() and init_user_exec()
>> because both of them are doing similar things.
>> (init_user_exec() just skips init vmlinux related
>>  symbol maps)
>>
>> Changes from v2:
>>  - Not to set symbol_conf.try_vmlinux_path in init_symbol_maps()
>>    (Thanks to Namhyung Kim!)
>>
>> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> 
> [SNIP]
>> -int show_line_range(struct line_range *lr, const char *module)
>> +static int __show_line_range(struct line_range *lr, const char *module)
>>  {
>>  	int l = 1;
>>  	struct line_node *ln;
>> @@ -573,10 +568,6 @@ int show_line_range(struct line_range *lr, const char *module)
>>  	char *tmp;
>>  
>>  	/* Search a line range */
>> -	ret = init_vmlinux();
>> -	if (ret < 0)
>> -		return ret;
>> -
>>  	dinfo = open_debuginfo(module);
>>  	if (!dinfo) {
>>  		pr_warning("Failed to open debuginfo file.\n");
>> @@ -646,6 +637,19 @@ end:
>>  	return ret;
>>  }
>>  
>> +int show_line_range(struct line_range *lr, const char *module)
>> +{
>> +	int ret;
>> +
>> +	ret = init_symbol_maps(false);
>> +	if (ret < 0)
>> +		return ret;
>> +	ret = __show_line_range(lr, module);
>> +	exit_symbol_maps();
> 
> Wouldn't it be better moving init/exit_symbol_maps() to a common
> location if they're used by every operations?

Oh, that's a good idea.:)
Since this just introduces init/exit_symbol_maps() to fix issue
by replacing old one. I think it's better to be done after this series.

Thank you,



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



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

* Re: [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo
  2014-02-14  5:43 ` [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
@ 2014-02-17 18:28   ` Arnaldo Carvalho de Melo
  2014-02-17 19:04     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-02-17 18:28 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Em Fri, Feb 14, 2014 at 02:43:12PM +0900, Masami Hiramatsu escreveu:
> Ping? :)

One patch didn't apply, 10/11, and it does't passes the build tests,
please try this before submitting patches:

[acme@zoo linux]$ make -C tools/perf build-test
make: Entering directory `/home/git/linux/tools/perf'
- make_pure: cd . && make -f Makefile DESTDIR=/tmp/tmp.yQDeWAV994 
make[1]: *** [make_pure] Error 1
make: *** [build-test] Error 2
make: Leaving directory `/home/git/linux/tools/perf'
[acme@zoo linux]$`

Failed the first test, to check what was that failed, do this:

[acme@zoo linux]$ tail -9 tools/perf/make_pure 
gcc -o ui/helpline.o -c  -Wbad-function-cast -Wdeclaration-after-statement -Wformat-security -Wformat-y2k -Winit-self -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wno-system-headers -Wold-style-definition -Wpacked -Wredundant-decls -Wshadow -Wstrict-aliasing=3 -Wstrict-prototypes -Wswitch-default -Wswitch-enum -Wundef -Wwrite-strings -Wformat -DHAVE_ARCH_X86_64_SUPPORT -DHAVE_PERF_REGS_SUPPORT -Werror -O6 -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 -fstack-protector-all -D_FORTIFY_SOURCE=2 -I/home/git/linux/tools/perf/util/include -I/home/git/linux/tools/perf/arch/x86/include -I/home/git/linux/tools/include/ -I/home/git/linux/arch/x86/include/uapi -I/home/git/linux/arch/x86/include -I/home/git/linux/include/uapi -I/home/git/linux/include -I/home/git/linux/tools/perf/util -I/home/git/linux/tools/perf -I/home/git/linux/tools/lib/ -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DHAVE_LIBELF_SUPPORT -DHAVE_LIBELF_MMAP_SUPPORT -DHAVE_ELF_GETPHDRNUM_SUPPORT -DHAVE_DWARF_SUPPORT  -DNO_LIBUNWIND_DEBUG_FRAME -DHAVE_DWARF_UNWIND_SUPPORT -DHAVE_LIBUNWIND_SUPPORT  -DHAVE_LIBAUDIT_SUPPORT -I/usr/include/slang -DHAVE_SLANG_SUPPORT -DHAVE_GTK2_SUPPORT -DHAVE_TIMERFD_SUPPORT -DHAVE_LIBBFD_SUPPORT -DHAVE_ON_EXIT_SUPPORT -DHAVE_BACKTRACE_SUPPORT -DHAVE_LIBNUMA_SUPPORT ui/helpline.c
util/probe-event.c: In function ‘add_exec_to_probe_trace_events’:
util/probe-event.c:369:3: error: ‘offset’ undeclared (first use in this function)
util/probe-event.c:369:3: note: each undeclared identifier is reported only once for each function it appears in
util/probe-event.c:373:20: error: ‘buf’ undeclared (first use in this function)
make[3]: *** [util/probe-event.o] Error 1
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [all] Error 2
  test: test -x ./perf
[acme@zoo linux]$

So that lots of tests with multiple combos of features are performed.

Thanks,

- Arnaldo
 
> (2014/02/06 14:32), Masami Hiramatsu wrote:
> > Hi,
> > 
> > Here is the 3rd version of the series for handling local
> > functions correctly with perf-probe. This version also
> > includes distro debuginfo-file support (a small
> > enhancement, based on existing feature).
> > 
> > In this version, I used ref_reloc_sym based probe point
> > instead of absolute address/"_stext", because kASLR
> > changes the address offset randomly and the debuginfo
> > doesn't know that offset. Recently perftools supports
> > kASLR by introducing ref_reloc_sym (which is usually
> > "_text" or "_stext"). Since we already ensured that
> > the kmap->ref_reloc_sym symbol exists in the kernel,
> > it is safe to reuse it for the reference point of
> > probe points.
> > 
> > Note that this series requires a bugfix patch:
> >   perf-probe: Do not add offset to uprobe address
> >   https://lkml.org/lkml/2014/2/5/7
> > 
> > 
> > Issue 1)
> >  Current perf-probe can't handle probe-points for kprobes,
> >  since it uses symbol-based probe definition. The symbol
> >  based definition is easy to read and robust for differnt
> >  kernel and modules. However, when user gives a local
> >  function name which has several different instances,
> >  it may put probes on wrong (or unexpected) address.
> >  On the other hand, since uprobe events are based on the
> >  actual address, it can avoid this issue.
> > 
> >  E.g.
> > In the case to probe t_show local functions (which has
> > 4 different instances.
> >   ----
> >   # grep " t_show\$" /proc/kallsyms
> >   ffffffff810d9720 t t_show
> >   ffffffff810e2e40 t t_show
> >   ffffffff810ece30 t t_show
> >   ffffffff810f4ad0 t t_show
> >   # ./perf probe -fa "t_show \$vars"
> >   Added new events:
> >     probe:t_show         (on t_show with $vars)
> >     probe:t_show_1       (on t_show with $vars)
> >     probe:t_show_2       (on t_show with $vars)
> >     probe:t_show_3       (on t_show with $vars)
> > 
> >   You can now use it in all perf tools, such as:
> > 
> >           perf record -e probe:t_show_3 -aR sleep 1
> >   ----
> > OK, we have 4 different t_show()s. All functions have
> > different arguments as below;
> >   ----
> >   # cat /sys/kernel/debug/tracing/kprobe_events
> >   p:probe/t_show t_show m=%di:u64 v=%si:u64
> >   p:probe/t_show_1 t_show m=%di:u64 v=%si:u64 t=%si:u64
> >   p:probe/t_show_2 t_show m=%di:u64 v=%si:u64 fmt=%si:u64
> >   p:probe/t_show_3 t_show m=%di:u64 v=%si:u64 file=%si:u64
> >   ----
> > However, all of them have been put on the *same* address.
> >   ----
> >   # cat /sys/kernel/debug/kprobes/list
> >   ffffffff810d9720  k  t_show+0x0    [DISABLED]
> >   ffffffff810d9720  k  t_show+0x0    [DISABLED]
> >   ffffffff810d9720  k  t_show+0x0    [DISABLED]
> >   ffffffff810d9720  k  t_show+0x0    [DISABLED]
> >   ----
> >  oops...
> > 
> > Issue 2)
> >  With the debuginfo, issue 1 can be solved by using
> >  _stext-based probe definition instead of local symbol-based.
> >  However, without debuginfo, perf-probe can only use
> >  symbol-map in the binary (or kallsyms). The map provides
> >  symbol find methods, but it returns only the first matched
> >  symbol. To put probes on all functions which have given
> >  symbol, we need a symbol-list iterator for the map.
> > 
> >  E.g. (built perf with NO_DWARF=1)
> > In the case to probe t_show and identity__map_ip in perf.
> >   ----
> >   # ./perf probe -a t_show
> >   Added new event:
> >     probe:t_show         (on t_show)
> > 
> >   You can now use it in all perf tools, such as:
> > 
> >           perf record -e probe:t_show -aR sleep 1
> > 
> >   # ./perf probe -x perf -a identity__map_ip
> >   no symbols found in /kbuild/ksrc/linux-3/tools/perf/perf, maybe install a debug package?
> >   Failed to load map.
> >     Error: Failed to add events. (-22)
> >   ----
> >  oops.....
> > 
> > 
> > Solutions)
> > To solve the issue 1, this series changes perf probe to
> > use _stext-based probe definition. This means that we
> > also need to fix the --list options to analyze actual
> > probe address from _stext address. (and that has been
> > done in this series).
> > 
> > E.g. with this series;
> >   ----
> >   # ./perf probe -a "t_show \$vars"
> >   Added new events:
> >     probe:t_show         (on t_show with $vars)
> >     probe:t_show_1       (on t_show with $vars)
> >     probe:t_show_2       (on t_show with $vars)
> >     probe:t_show_3       (on t_show with $vars)
> > 
> >   You can now use it in all perf tools, such as:
> > 
> >           perf record -e probe:t_show_3 -aR sleep 1
> > 
> >   # cat /sys/kernel/debug/tracing/kprobe_events
> >   p:probe/t_show _stext+889880 m=%di:u64 v=%si:u64
> >   p:probe/t_show_1 _stext+928568 m=%di:u64 v=%si:u64 t=%si:u64
> >   p:probe/t_show_2 _stext+969512 m=%di:u64 v=%si:u64 fmt=%si:u64
> >   p:probe/t_show_3 _stext+1001416 m=%di:u64 v=%si:u64 file=%si:u64
> > 
> >   # cat /sys/kernel/debug/kprobes/list
> >   ffffffffb50d95e0  k  t_show+0x0    [DISABLED]
> >   ffffffffb50e2d00  k  t_show+0x0    [DISABLED]
> >   ffffffffb50f4990  k  t_show+0x0    [DISABLED]
> >   ffffffffb50eccf0  k  t_show+0x0    [DISABLED]
> >   ----
> > This time we can see the events are set in different
> > addresses.
> > 
> > And for the issue 2, the last patch introduces symbol
> > iterators for map, dso and symbols (since the symbol
> > list is the symbols and it is included in dso, and perf
> > probe accesses dso via map).
> > 
> > E.g. with this series (built perf with NO_DWARF=1);
> >   ----
> >   # ./perf probe -a t_show
> >   Added new events:
> >     probe:t_show         (on t_show)
> >     probe:t_show_1       (on t_show)
> >     probe:t_show_2       (on t_show)
> >     probe:t_show_3       (on t_show)
> > 
> >   You can now use it in all perf tools, such as:
> > 
> >           perf record -e probe:t_show_3 -aR sleep 1
> > 
> >   # ./perf probe -x perf -a identity__map_ip
> >   Added new events:
> >     probe_perf:identity__map_ip (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
> >     probe_perf:identity__map_ip_1 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
> >     probe_perf:identity__map_ip_2 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
> >     probe_perf:identity__map_ip_3 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
> > 
> >   You can now use it in all perf tools, such as:
> > 
> >           perf record -e probe_perf:identity__map_ip_3 -aR sleep 1
> >   ----
> > Now, even without the debuginfo, both the kprobe and
> > uprobe are set 4 different places correctly.
> > 
> > BTW, while testing above, I've found some bugs and
> > another minor issue; perf-probe doesn't show the
> > modules and binaries in which probes are set.
> > I've also fixed it in this series as below.
> > 
> > Without the fix;
> > 
> >   # ./perf probe -m drm drm_av_sync_delay
> >   # ./perf probe -x perf dso__load_vmlinux
> > 
> >   # ./perf probe -l
> >     probe:drm_av_sync_delay (on drm_av_sync_delay)
> >     probe_perf:dso__load_vmlinux (on 0x000000000006d110)
> > 
> > With this fix;
> > 
> >   # ./perf probe -l
> >     probe:drm_av_sync_delay (on drm_av_sync_delay in drm)
> >     probe_perf:dso__load_vmlinux (on 0x000000000006d110 in /kbuild/ksrc/linux-3/tools/perf/perf)
> > 
> > Changes from v2:
> >  - Use ref_reloc_sym instead of "_stext" for reference point.
> >    (Thanks for Namhyung Kim!)
> >  - Add 2 cleanup patches for reducing the redundant features.
> >  - Add distro-style debuginfo support.
> > 
> > TODO:
> >  - Support local functions in modules. This requires kernel
> >  side enhancement to allow setting probes by the relative
> >  addresses in modules too.
> >  - Uprobe-event MUST traces the change of given binary even
> >  when the event is disabled. I've found that user can replace
> >  the target binary after setting events and the events can be
> >  enabled on the different instructions...
> > 
> > ---
> > 
> > Masami Hiramatsu (11):
> >       [BUGFIX] perf-probe: Fix to do exit call for symbol maps
> >       [CLEANUP] perf-probe: Remove incorrect symbol check for --list
> >       [CLEANUP] perf-probe: Replace line_list with intlist
> >       [CLEANUP] perf-probe: Unify show_available_functions for uprobes/kprobes
> >       perf-probe: Show in what binaries/modules probes are set
> >       perf-probe: Use ref_reloc_sym based address instead of the symbol name
> >       perf-probe: Find given address from offline dwarf
> >       perf-probe: Show appropriate symbol for ref_reloc_sym based kprobes
> >       perf-probe: Show source-level or symbol-level info for uprobes
> >       perf-probe: Allow to add events on the local functions
> >       perf probe: Support distro-style debuginfo for uprobe
> > 
> > 
> >  tools/perf/builtin-probe.c     |   12 -
> >  tools/perf/util/dso.h          |   10 
> >  tools/perf/util/map.h          |   10 
> >  tools/perf/util/probe-event.c  |  863 ++++++++++++++++++++++------------------
> >  tools/perf/util/probe-event.h  |   12 -
> >  tools/perf/util/probe-finder.c |  198 ++-------
> >  tools/perf/util/probe-finder.h |    5 
> >  tools/perf/util/symbol.h       |   11 +
> >  8 files changed, 566 insertions(+), 555 deletions(-)
> > 
> 
> 
> -- 
> Masami HIRAMATSU
> IT Management Research Dept. Linux Technology Center
> Hitachi, Ltd., Yokohama Research Laboratory
> E-mail: masami.hiramatsu.pt@hitachi.com
> 

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

* Re: [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo
  2014-02-17 18:28   ` Arnaldo Carvalho de Melo
@ 2014-02-17 19:04     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 29+ messages in thread
From: Arnaldo Carvalho de Melo @ 2014-02-17 19:04 UTC (permalink / raw)
  To: Masami Hiramatsu
  Cc: Srikar Dronamraju, David Ahern, linux-kernel,
	Steven Rostedt (Red Hat),
	Oleg Nesterov, Ingo Molnar, David A. Long, yrl.pp-manager.tt,
	Namhyung Kim

Em Mon, Feb 17, 2014 at 03:28:00PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Fri, Feb 14, 2014 at 02:43:12PM +0900, Masami Hiramatsu escreveu:
> > Ping? :)
> 
> One patch didn't apply, 10/11, and it does't passes the build tests,
> please try this before submitting patches:

Sorry, that was me trying to apply the patch that didn't pass, then when
I went to run 'make -C tools/perf build-test', it was using the sources
with the broken patch, now running after removing it, i.e. all patches
applied minus [PATCH 10/11]

- Arnaldo
 
> [acme@zoo linux]$ make -C tools/perf build-test
> make: Entering directory `/home/git/linux/tools/perf'
> - make_pure: cd . && make -f Makefile DESTDIR=/tmp/tmp.yQDeWAV994 
> make[1]: *** [make_pure] Error 1
> make: *** [build-test] Error 2
> make: Leaving directory `/home/git/linux/tools/perf'
> [acme@zoo linux]$`
> 
> Failed the first test, to check what was that failed, do this:
> 
> [acme@zoo linux]$ tail -9 tools/perf/make_pure 
> gcc -o ui/helpline.o -c  -Wbad-function-cast -Wdeclaration-after-statement -Wformat-security -Wformat-y2k -Winit-self -Wmissing-declarations -Wmissing-prototypes -Wnested-externs -Wno-system-headers -Wold-style-definition -Wpacked -Wredundant-decls -Wshadow -Wstrict-aliasing=3 -Wstrict-prototypes -Wswitch-default -Wswitch-enum -Wundef -Wwrite-strings -Wformat -DHAVE_ARCH_X86_64_SUPPORT -DHAVE_PERF_REGS_SUPPORT -Werror -O6 -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 -fstack-protector-all -D_FORTIFY_SOURCE=2 -I/home/git/linux/tools/perf/util/include -I/home/git/linux/tools/perf/arch/x86/include -I/home/git/linux/tools/include/ -I/home/git/linux/arch/x86/include/uapi -I/home/git/linux/arch/x86/include -I/home/git/linux/include/uapi -I/home/git/linux/include -I/home/git/linux/tools/perf/util -I/home/git/linux/tools/perf -I/home/git/linux/tools/lib/ -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DHAVE_LIBELF_SUPPORT -DHAVE_LIBELF_MMAP_SUPPORT -DHAVE_ELF_GETPHDRNUM_SUPPORT -DHAVE_DWARF_SUPPORT  -DNO_LIBUNWIND_DEBUG_FRAME -DHAVE_DWARF_UNWIND_SUPPORT -DHAVE_LIBUNWIND_SUPPORT  -DHAVE_LIBAUDIT_SUPPORT -I/usr/include/slang -DHAVE_SLANG_SUPPORT -DHAVE_GTK2_SUPPORT -DHAVE_TIMERFD_SUPPORT -DHAVE_LIBBFD_SUPPORT -DHAVE_ON_EXIT_SUPPORT -DHAVE_BACKTRACE_SUPPORT -DHAVE_LIBNUMA_SUPPORT ui/helpline.c
> util/probe-event.c: In function ‘add_exec_to_probe_trace_events’:
> util/probe-event.c:369:3: error: ‘offset’ undeclared (first use in this function)
> util/probe-event.c:369:3: note: each undeclared identifier is reported only once for each function it appears in
> util/probe-event.c:373:20: error: ‘buf’ undeclared (first use in this function)
> make[3]: *** [util/probe-event.o] Error 1
> make[3]: *** Waiting for unfinished jobs....
> make[2]: *** [all] Error 2
>   test: test -x ./perf
> [acme@zoo linux]$
> 
> So that lots of tests with multiple combos of features are performed.
> 
> Thanks,
> 
> - Arnaldo
>  
> > (2014/02/06 14:32), Masami Hiramatsu wrote:
> > > Hi,
> > > 
> > > Here is the 3rd version of the series for handling local
> > > functions correctly with perf-probe. This version also
> > > includes distro debuginfo-file support (a small
> > > enhancement, based on existing feature).
> > > 
> > > In this version, I used ref_reloc_sym based probe point
> > > instead of absolute address/"_stext", because kASLR
> > > changes the address offset randomly and the debuginfo
> > > doesn't know that offset. Recently perftools supports
> > > kASLR by introducing ref_reloc_sym (which is usually
> > > "_text" or "_stext"). Since we already ensured that
> > > the kmap->ref_reloc_sym symbol exists in the kernel,
> > > it is safe to reuse it for the reference point of
> > > probe points.
> > > 
> > > Note that this series requires a bugfix patch:
> > >   perf-probe: Do not add offset to uprobe address
> > >   https://lkml.org/lkml/2014/2/5/7
> > > 
> > > 
> > > Issue 1)
> > >  Current perf-probe can't handle probe-points for kprobes,
> > >  since it uses symbol-based probe definition. The symbol
> > >  based definition is easy to read and robust for differnt
> > >  kernel and modules. However, when user gives a local
> > >  function name which has several different instances,
> > >  it may put probes on wrong (or unexpected) address.
> > >  On the other hand, since uprobe events are based on the
> > >  actual address, it can avoid this issue.
> > > 
> > >  E.g.
> > > In the case to probe t_show local functions (which has
> > > 4 different instances.
> > >   ----
> > >   # grep " t_show\$" /proc/kallsyms
> > >   ffffffff810d9720 t t_show
> > >   ffffffff810e2e40 t t_show
> > >   ffffffff810ece30 t t_show
> > >   ffffffff810f4ad0 t t_show
> > >   # ./perf probe -fa "t_show \$vars"
> > >   Added new events:
> > >     probe:t_show         (on t_show with $vars)
> > >     probe:t_show_1       (on t_show with $vars)
> > >     probe:t_show_2       (on t_show with $vars)
> > >     probe:t_show_3       (on t_show with $vars)
> > > 
> > >   You can now use it in all perf tools, such as:
> > > 
> > >           perf record -e probe:t_show_3 -aR sleep 1
> > >   ----
> > > OK, we have 4 different t_show()s. All functions have
> > > different arguments as below;
> > >   ----
> > >   # cat /sys/kernel/debug/tracing/kprobe_events
> > >   p:probe/t_show t_show m=%di:u64 v=%si:u64
> > >   p:probe/t_show_1 t_show m=%di:u64 v=%si:u64 t=%si:u64
> > >   p:probe/t_show_2 t_show m=%di:u64 v=%si:u64 fmt=%si:u64
> > >   p:probe/t_show_3 t_show m=%di:u64 v=%si:u64 file=%si:u64
> > >   ----
> > > However, all of them have been put on the *same* address.
> > >   ----
> > >   # cat /sys/kernel/debug/kprobes/list
> > >   ffffffff810d9720  k  t_show+0x0    [DISABLED]
> > >   ffffffff810d9720  k  t_show+0x0    [DISABLED]
> > >   ffffffff810d9720  k  t_show+0x0    [DISABLED]
> > >   ffffffff810d9720  k  t_show+0x0    [DISABLED]
> > >   ----
> > >  oops...
> > > 
> > > Issue 2)
> > >  With the debuginfo, issue 1 can be solved by using
> > >  _stext-based probe definition instead of local symbol-based.
> > >  However, without debuginfo, perf-probe can only use
> > >  symbol-map in the binary (or kallsyms). The map provides
> > >  symbol find methods, but it returns only the first matched
> > >  symbol. To put probes on all functions which have given
> > >  symbol, we need a symbol-list iterator for the map.
> > > 
> > >  E.g. (built perf with NO_DWARF=1)
> > > In the case to probe t_show and identity__map_ip in perf.
> > >   ----
> > >   # ./perf probe -a t_show
> > >   Added new event:
> > >     probe:t_show         (on t_show)
> > > 
> > >   You can now use it in all perf tools, such as:
> > > 
> > >           perf record -e probe:t_show -aR sleep 1
> > > 
> > >   # ./perf probe -x perf -a identity__map_ip
> > >   no symbols found in /kbuild/ksrc/linux-3/tools/perf/perf, maybe install a debug package?
> > >   Failed to load map.
> > >     Error: Failed to add events. (-22)
> > >   ----
> > >  oops.....
> > > 
> > > 
> > > Solutions)
> > > To solve the issue 1, this series changes perf probe to
> > > use _stext-based probe definition. This means that we
> > > also need to fix the --list options to analyze actual
> > > probe address from _stext address. (and that has been
> > > done in this series).
> > > 
> > > E.g. with this series;
> > >   ----
> > >   # ./perf probe -a "t_show \$vars"
> > >   Added new events:
> > >     probe:t_show         (on t_show with $vars)
> > >     probe:t_show_1       (on t_show with $vars)
> > >     probe:t_show_2       (on t_show with $vars)
> > >     probe:t_show_3       (on t_show with $vars)
> > > 
> > >   You can now use it in all perf tools, such as:
> > > 
> > >           perf record -e probe:t_show_3 -aR sleep 1
> > > 
> > >   # cat /sys/kernel/debug/tracing/kprobe_events
> > >   p:probe/t_show _stext+889880 m=%di:u64 v=%si:u64
> > >   p:probe/t_show_1 _stext+928568 m=%di:u64 v=%si:u64 t=%si:u64
> > >   p:probe/t_show_2 _stext+969512 m=%di:u64 v=%si:u64 fmt=%si:u64
> > >   p:probe/t_show_3 _stext+1001416 m=%di:u64 v=%si:u64 file=%si:u64
> > > 
> > >   # cat /sys/kernel/debug/kprobes/list
> > >   ffffffffb50d95e0  k  t_show+0x0    [DISABLED]
> > >   ffffffffb50e2d00  k  t_show+0x0    [DISABLED]
> > >   ffffffffb50f4990  k  t_show+0x0    [DISABLED]
> > >   ffffffffb50eccf0  k  t_show+0x0    [DISABLED]
> > >   ----
> > > This time we can see the events are set in different
> > > addresses.
> > > 
> > > And for the issue 2, the last patch introduces symbol
> > > iterators for map, dso and symbols (since the symbol
> > > list is the symbols and it is included in dso, and perf
> > > probe accesses dso via map).
> > > 
> > > E.g. with this series (built perf with NO_DWARF=1);
> > >   ----
> > >   # ./perf probe -a t_show
> > >   Added new events:
> > >     probe:t_show         (on t_show)
> > >     probe:t_show_1       (on t_show)
> > >     probe:t_show_2       (on t_show)
> > >     probe:t_show_3       (on t_show)
> > > 
> > >   You can now use it in all perf tools, such as:
> > > 
> > >           perf record -e probe:t_show_3 -aR sleep 1
> > > 
> > >   # ./perf probe -x perf -a identity__map_ip
> > >   Added new events:
> > >     probe_perf:identity__map_ip (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
> > >     probe_perf:identity__map_ip_1 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
> > >     probe_perf:identity__map_ip_2 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
> > >     probe_perf:identity__map_ip_3 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
> > > 
> > >   You can now use it in all perf tools, such as:
> > > 
> > >           perf record -e probe_perf:identity__map_ip_3 -aR sleep 1
> > >   ----
> > > Now, even without the debuginfo, both the kprobe and
> > > uprobe are set 4 different places correctly.
> > > 
> > > BTW, while testing above, I've found some bugs and
> > > another minor issue; perf-probe doesn't show the
> > > modules and binaries in which probes are set.
> > > I've also fixed it in this series as below.
> > > 
> > > Without the fix;
> > > 
> > >   # ./perf probe -m drm drm_av_sync_delay
> > >   # ./perf probe -x perf dso__load_vmlinux
> > > 
> > >   # ./perf probe -l
> > >     probe:drm_av_sync_delay (on drm_av_sync_delay)
> > >     probe_perf:dso__load_vmlinux (on 0x000000000006d110)
> > > 
> > > With this fix;
> > > 
> > >   # ./perf probe -l
> > >     probe:drm_av_sync_delay (on drm_av_sync_delay in drm)
> > >     probe_perf:dso__load_vmlinux (on 0x000000000006d110 in /kbuild/ksrc/linux-3/tools/perf/perf)
> > > 
> > > Changes from v2:
> > >  - Use ref_reloc_sym instead of "_stext" for reference point.
> > >    (Thanks for Namhyung Kim!)
> > >  - Add 2 cleanup patches for reducing the redundant features.
> > >  - Add distro-style debuginfo support.
> > > 
> > > TODO:
> > >  - Support local functions in modules. This requires kernel
> > >  side enhancement to allow setting probes by the relative
> > >  addresses in modules too.
> > >  - Uprobe-event MUST traces the change of given binary even
> > >  when the event is disabled. I've found that user can replace
> > >  the target binary after setting events and the events can be
> > >  enabled on the different instructions...
> > > 
> > > ---
> > > 
> > > Masami Hiramatsu (11):
> > >       [BUGFIX] perf-probe: Fix to do exit call for symbol maps
> > >       [CLEANUP] perf-probe: Remove incorrect symbol check for --list
> > >       [CLEANUP] perf-probe: Replace line_list with intlist
> > >       [CLEANUP] perf-probe: Unify show_available_functions for uprobes/kprobes
> > >       perf-probe: Show in what binaries/modules probes are set
> > >       perf-probe: Use ref_reloc_sym based address instead of the symbol name
> > >       perf-probe: Find given address from offline dwarf
> > >       perf-probe: Show appropriate symbol for ref_reloc_sym based kprobes
> > >       perf-probe: Show source-level or symbol-level info for uprobes
> > >       perf-probe: Allow to add events on the local functions
> > >       perf probe: Support distro-style debuginfo for uprobe
> > > 
> > > 
> > >  tools/perf/builtin-probe.c     |   12 -
> > >  tools/perf/util/dso.h          |   10 
> > >  tools/perf/util/map.h          |   10 
> > >  tools/perf/util/probe-event.c  |  863 ++++++++++++++++++++++------------------
> > >  tools/perf/util/probe-event.h  |   12 -
> > >  tools/perf/util/probe-finder.c |  198 ++-------
> > >  tools/perf/util/probe-finder.h |    5 
> > >  tools/perf/util/symbol.h       |   11 +
> > >  8 files changed, 566 insertions(+), 555 deletions(-)
> > > 
> > 
> > 
> > -- 
> > Masami HIRAMATSU
> > IT Management Research Dept. Linux Technology Center
> > Hitachi, Ltd., Yokohama Research Laboratory
> > E-mail: masami.hiramatsu.pt@hitachi.com
> > 

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

* [tip:perf/core] perf probe: Fix to do exit call for symbol maps
  2014-02-06  5:32 ` [PATCH -tip v3 01/11] [BUGFIX] perf-probe: Fix to do exit call for symbol maps Masami Hiramatsu
  2014-02-17  7:56   ` Namhyung Kim
@ 2014-02-22 17:59   ` tip-bot for Masami Hiramatsu
  1 sibling, 0 replies; 29+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2014-02-22 17:59 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, mingo, dave.long, hpa, mingo, namhyung,
	masami.hiramatsu.pt, rostedt, srikar, dsahern, oleg, tglx

Commit-ID:  ee45b6c2c52d4217aae82eb2e8136fa2f8b93303
Gitweb:     http://git.kernel.org/tip/ee45b6c2c52d4217aae82eb2e8136fa2f8b93303
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 6 Feb 2014 05:32:04 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 18 Feb 2014 09:34:50 -0300

perf probe: Fix to do exit call for symbol maps

Some perf-probe commands do symbol_init() but doesn't do exit call.

This fixes that to call symbol_exit() and releases machine if needed.

This also merges init_vmlinux() and init_user_exec() because both of
them are doing similar things.  (init_user_exec() just skips init
vmlinux related symbol maps)

Changes from v2:
 - Not to set symbol_conf.try_vmlinux_path in init_symbol_maps()
   (Thanks to Namhyung Kim!)

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: "David A. Long" <dave.long@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20140206053204.29635.28334.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-event.c | 104 +++++++++++++++++++++++-------------------
 1 file changed, 56 insertions(+), 48 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index d8b048c..9aa7783 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -73,31 +73,31 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
 static int convert_name_to_addr(struct perf_probe_event *pev,
 				const char *exec);
 static void clear_probe_trace_event(struct probe_trace_event *tev);
-static struct machine machine;
+static struct machine *host_machine;
 
 /* Initialize symbol maps and path of vmlinux/modules */
-static int init_vmlinux(void)
+static int init_symbol_maps(bool user_only)
 {
 	int ret;
 
 	symbol_conf.sort_by_name = true;
-	if (symbol_conf.vmlinux_name == NULL)
-		symbol_conf.try_vmlinux_path = true;
-	else
-		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
 	ret = symbol__init();
 	if (ret < 0) {
 		pr_debug("Failed to init symbol map.\n");
 		goto out;
 	}
 
-	ret = machine__init(&machine, "", HOST_KERNEL_ID);
-	if (ret < 0)
-		goto out;
+	if (host_machine || user_only)	/* already initialized */
+		return 0;
 
-	if (machine__create_kernel_maps(&machine) < 0) {
-		pr_debug("machine__create_kernel_maps() failed.\n");
-		goto out;
+	if (symbol_conf.vmlinux_name)
+		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
+
+	host_machine = machine__new_host();
+	if (!host_machine) {
+		pr_debug("machine__new_host() failed.\n");
+		symbol__exit();
+		ret = -1;
 	}
 out:
 	if (ret < 0)
@@ -105,21 +105,30 @@ out:
 	return ret;
 }
 
+static void exit_symbol_maps(void)
+{
+	if (host_machine) {
+		machine__delete(host_machine);
+		host_machine = NULL;
+	}
+	symbol__exit();
+}
+
 static struct symbol *__find_kernel_function_by_name(const char *name,
 						     struct map **mapp)
 {
-	return machine__find_kernel_function_by_name(&machine, name, mapp,
+	return machine__find_kernel_function_by_name(host_machine, name, mapp,
 						     NULL);
 }
 
 static struct map *kernel_get_module_map(const char *module)
 {
 	struct rb_node *nd;
-	struct map_groups *grp = &machine.kmaps;
+	struct map_groups *grp = &host_machine->kmaps;
 
 	/* A file path -- this is an offline module */
 	if (module && strchr(module, '/'))
-		return machine__new_module(&machine, 0, module);
+		return machine__new_module(host_machine, 0, module);
 
 	if (!module)
 		module = "kernel";
@@ -141,7 +150,7 @@ static struct dso *kernel_get_module_dso(const char *module)
 	const char *vmlinux_name;
 
 	if (module) {
-		list_for_each_entry(dso, &machine.kernel_dsos, node) {
+		list_for_each_entry(dso, &host_machine->kernel_dsos, node) {
 			if (strncmp(dso->short_name + 1, module,
 				    dso->short_name_len - 2) == 0)
 				goto found;
@@ -150,7 +159,7 @@ static struct dso *kernel_get_module_dso(const char *module)
 		return NULL;
 	}
 
-	map = machine.vmlinux_maps[MAP__FUNCTION];
+	map = host_machine->vmlinux_maps[MAP__FUNCTION];
 	dso = map->dso;
 
 	vmlinux_name = symbol_conf.vmlinux_name;
@@ -173,20 +182,6 @@ const char *kernel_get_module_path(const char *module)
 	return (dso) ? dso->long_name : NULL;
 }
 
-static int init_user_exec(void)
-{
-	int ret = 0;
-
-	symbol_conf.try_vmlinux_path = false;
-	symbol_conf.sort_by_name = true;
-	ret = symbol__init();
-
-	if (ret < 0)
-		pr_debug("Failed to init symbol map.\n");
-
-	return ret;
-}
-
 static int convert_exec_to_group(const char *exec, char **result)
 {
 	char *ptr1, *ptr2, *exec_copy;
@@ -563,7 +558,7 @@ static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
  * Show line-range always requires debuginfo to find source file and
  * line number.
  */
-int show_line_range(struct line_range *lr, const char *module)
+static int __show_line_range(struct line_range *lr, const char *module)
 {
 	int l = 1;
 	struct line_node *ln;
@@ -573,10 +568,6 @@ int show_line_range(struct line_range *lr, const char *module)
 	char *tmp;
 
 	/* Search a line range */
-	ret = init_vmlinux();
-	if (ret < 0)
-		return ret;
-
 	dinfo = open_debuginfo(module);
 	if (!dinfo) {
 		pr_warning("Failed to open debuginfo file.\n");
@@ -646,6 +637,19 @@ end:
 	return ret;
 }
 
+int show_line_range(struct line_range *lr, const char *module)
+{
+	int ret;
+
+	ret = init_symbol_maps(false);
+	if (ret < 0)
+		return ret;
+	ret = __show_line_range(lr, module);
+	exit_symbol_maps();
+
+	return ret;
+}
+
 static int show_available_vars_at(struct debuginfo *dinfo,
 				  struct perf_probe_event *pev,
 				  int max_vls, struct strfilter *_filter,
@@ -707,14 +711,15 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
 	int i, ret = 0;
 	struct debuginfo *dinfo;
 
-	ret = init_vmlinux();
+	ret = init_symbol_maps(false);
 	if (ret < 0)
 		return ret;
 
 	dinfo = open_debuginfo(module);
 	if (!dinfo) {
 		pr_warning("Failed to open debuginfo file.\n");
-		return -ENOENT;
+		ret = -ENOENT;
+		goto out;
 	}
 
 	setup_pager();
@@ -724,6 +729,8 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
 					     externs);
 
 	debuginfo__delete(dinfo);
+out:
+	exit_symbol_maps();
 	return ret;
 }
 
@@ -1807,7 +1814,7 @@ int show_perf_probe_events(void)
 	if (fd < 0)
 		return fd;
 
-	ret = init_vmlinux();
+	ret = init_symbol_maps(false);
 	if (ret < 0)
 		return ret;
 
@@ -1820,6 +1827,7 @@ int show_perf_probe_events(void)
 		close(fd);
 	}
 
+	exit_symbol_maps();
 	return ret;
 }
 
@@ -2135,12 +2143,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
 	if (pkgs == NULL)
 		return -ENOMEM;
 
-	if (!pevs->uprobes)
-		/* Init vmlinux path */
-		ret = init_vmlinux();
-	else
-		ret = init_user_exec();
-
+	ret = init_symbol_maps(pevs->uprobes);
 	if (ret < 0) {
 		free(pkgs);
 		return ret;
@@ -2174,6 +2177,7 @@ end:
 		zfree(&pkgs[i].tevs);
 	}
 	free(pkgs);
+	exit_symbol_maps();
 
 	return ret;
 }
@@ -2347,7 +2351,7 @@ static int available_kernel_funcs(const char *module)
 	struct map *map;
 	int ret;
 
-	ret = init_vmlinux();
+	ret = init_symbol_maps(false);
 	if (ret < 0)
 		return ret;
 
@@ -2356,7 +2360,10 @@ static int available_kernel_funcs(const char *module)
 		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
 		return -EINVAL;
 	}
-	return __show_available_funcs(map);
+	ret = __show_available_funcs(map);
+	exit_symbol_maps();
+
+	return ret;
 }
 
 static int available_user_funcs(const char *target)
@@ -2364,7 +2371,7 @@ static int available_user_funcs(const char *target)
 	struct map *map;
 	int ret;
 
-	ret = init_user_exec();
+	ret = init_symbol_maps(true);
 	if (ret < 0)
 		return ret;
 
@@ -2372,6 +2379,7 @@ static int available_user_funcs(const char *target)
 	ret = __show_available_funcs(map);
 	dso__delete(map->dso);
 	map__delete(map);
+	exit_symbol_maps();
 	return ret;
 }
 

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

* [tip:perf/core] perf probe: Remove incorrect symbol check for --list
  2014-02-06  5:32 ` [PATCH -tip v3 02/11] [CLEANUP] perf-probe: Remove incorrect symbol check for --list Masami Hiramatsu
@ 2014-02-22 18:00   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 29+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2014-02-22 18:00 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, mingo, dave.long, hpa, mingo, namhyung,
	masami.hiramatsu.pt, rostedt, srikar, dsahern, oleg, tglx

Commit-ID:  f49540b17c1c6fa5a0734cc1d8b57614fd2036be
Gitweb:     http://git.kernel.org/tip/f49540b17c1c6fa5a0734cc1d8b57614fd2036be
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 6 Feb 2014 05:32:06 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 18 Feb 2014 09:34:50 -0300

perf probe: Remove incorrect symbol check for --list

Remove unneeded symbol check for --list option.

This code actually checks whether the given symbol exists in the kernel.
But this is incorrect for online kernel/module and offline module too:

 - For online kernel/module, the kprobes itself already
  ensured the symbol exist in the kernel.
 - For offline module, this code can't access the offlined
  modules. Ignore it.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: "David A. Long" <dave.long@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20140206053206.29635.7453.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-event.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 9aa7783..a4649e7 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -739,14 +739,6 @@ out:
 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 					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;
-	}
-
 	return convert_to_perf_probe_point(tp, pp);
 }
 

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

* [tip:perf/core] perf probe: Replace line_list with intlist
  2014-02-06  5:32 ` [PATCH -tip v3 03/11] [CLEANUP] perf-probe: Replace line_list with intlist Masami Hiramatsu
  2014-02-17  7:58   ` Namhyung Kim
@ 2014-02-22 18:00   ` tip-bot for Masami Hiramatsu
  1 sibling, 0 replies; 29+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2014-02-22 18:00 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, mingo, dave.long, hpa, mingo, namhyung,
	masami.hiramatsu.pt, rostedt, srikar, dsahern, oleg, tglx

Commit-ID:  5a62257a3ddd1a09cf278eae0697fcbe20897447
Gitweb:     http://git.kernel.org/tip/5a62257a3ddd1a09cf278eae0697fcbe20897447
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 6 Feb 2014 05:32:09 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 18 Feb 2014 09:34:50 -0300

perf probe: Replace line_list with intlist

Replace line_list (struct line_node) with intlist for reducing similar
codes.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: "David A. Long" <dave.long@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20140206053209.29635.81043.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-probe.c     | 12 ++++---
 tools/perf/util/probe-event.c  | 22 ++++++------
 tools/perf/util/probe-event.h  | 12 ++-----
 tools/perf/util/probe-finder.c | 81 +++++++-----------------------------------
 tools/perf/util/probe-finder.h |  3 +-
 5 files changed, 35 insertions(+), 95 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 7894888..cdcd4eb 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -268,9 +268,9 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
 	return 0;
 }
 
-static void init_params(void)
+static int init_params(void)
 {
-	line_range__init(&params.line_range);
+	return line_range__init(&params.line_range);
 }
 
 static void cleanup_params(void)
@@ -515,9 +515,11 @@ int cmd_probe(int argc, const char **argv, const char *prefix)
 {
 	int ret;
 
-	init_params();
-	ret = __cmd_probe(argc, argv, prefix);
-	cleanup_params();
+	ret = init_params();
+	if (!ret) {
+		ret = __cmd_probe(argc, argv, prefix);
+		cleanup_params();
+	}
 
 	return ret;
 }
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index a4649e7..f70fd08 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -561,7 +561,7 @@ static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
 static int __show_line_range(struct line_range *lr, const char *module)
 {
 	int l = 1;
-	struct line_node *ln;
+	struct int_node *ln;
 	struct debuginfo *dinfo;
 	FILE *fp;
 	int ret;
@@ -614,8 +614,8 @@ static int __show_line_range(struct line_range *lr, const char *module)
 			goto end;
 	}
 
-	list_for_each_entry(ln, &lr->line_list, list) {
-		for (; ln->line > l; l++) {
+	intlist__for_each(ln, lr->line_list) {
+		for (; ln->i > l; l++) {
 			ret = show_one_line(fp, l - lr->offset);
 			if (ret < 0)
 				goto end;
@@ -775,24 +775,22 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
 
 void line_range__clear(struct line_range *lr)
 {
-	struct line_node *ln;
-
 	free(lr->function);
 	free(lr->file);
 	free(lr->path);
 	free(lr->comp_dir);
-	while (!list_empty(&lr->line_list)) {
-		ln = list_first_entry(&lr->line_list, struct line_node, list);
-		list_del(&ln->list);
-		free(ln);
-	}
+	intlist__delete(lr->line_list);
 	memset(lr, 0, sizeof(*lr));
 }
 
-void line_range__init(struct line_range *lr)
+int line_range__init(struct line_range *lr)
 {
 	memset(lr, 0, sizeof(*lr));
-	INIT_LIST_HEAD(&lr->line_list);
+	lr->line_list = intlist__new(NULL);
+	if (!lr->line_list)
+		return -ENOMEM;
+	else
+		return 0;
 }
 
 static int parse_line_num(char **ptr, int *val, const char *what)
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index fcaf727..776c934 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -2,6 +2,7 @@
 #define _PROBE_EVENT_H
 
 #include <stdbool.h>
+#include "intlist.h"
 #include "strlist.h"
 #include "strfilter.h"
 
@@ -76,13 +77,6 @@ struct perf_probe_event {
 	struct perf_probe_arg	*args;	/* Arguments */
 };
 
-
-/* Line number container */
-struct line_node {
-	struct list_head	list;
-	int			line;
-};
-
 /* Line range */
 struct line_range {
 	char			*file;		/* File name */
@@ -92,7 +86,7 @@ struct line_range {
 	int			offset;		/* Start line offset */
 	char			*path;		/* Real path name */
 	char			*comp_dir;	/* Compile directory */
-	struct list_head	line_list;	/* Visible lines */
+	struct intlist		*line_list;	/* Visible lines */
 };
 
 /* List of variables */
@@ -124,7 +118,7 @@ extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
 extern void line_range__clear(struct line_range *lr);
 
 /* Initialize line range */
-extern void line_range__init(struct line_range *lr);
+extern int line_range__init(struct line_range *lr);
 
 /* Internal use: Return kernel/module path */
 extern const char *kernel_get_module_path(const char *module);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 061edb1..e5e589f 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -35,6 +35,7 @@
 #include <linux/bitops.h>
 #include "event.h"
 #include "debug.h"
+#include "intlist.h"
 #include "util.h"
 #include "symbol.h"
 #include "probe-finder.h"
@@ -42,65 +43,6 @@
 /* Kprobe tracer basic type is up to u64 */
 #define MAX_BASIC_TYPE_BITS	64
 
-/* Line number list operations */
-
-/* Add a line to line number list */
-static int line_list__add_line(struct list_head *head, int line)
-{
-	struct line_node *ln;
-	struct list_head *p;
-
-	/* Reverse search, because new line will be the last one */
-	list_for_each_entry_reverse(ln, head, list) {
-		if (ln->line < line) {
-			p = &ln->list;
-			goto found;
-		} else if (ln->line == line)	/* Already exist */
-			return 1;
-	}
-	/* List is empty, or the smallest entry */
-	p = head;
-found:
-	pr_debug("line list: add a line %u\n", line);
-	ln = zalloc(sizeof(struct line_node));
-	if (ln == NULL)
-		return -ENOMEM;
-	ln->line = line;
-	INIT_LIST_HEAD(&ln->list);
-	list_add(&ln->list, p);
-	return 0;
-}
-
-/* Check if the line in line number list */
-static int line_list__has_line(struct list_head *head, int line)
-{
-	struct line_node *ln;
-
-	/* Reverse search, because new line will be the last one */
-	list_for_each_entry(ln, head, list)
-		if (ln->line == line)
-			return 1;
-
-	return 0;
-}
-
-/* Init line number list */
-static void line_list__init(struct list_head *head)
-{
-	INIT_LIST_HEAD(head);
-}
-
-/* Free line number list */
-static void line_list__free(struct list_head *head)
-{
-	struct line_node *ln;
-	while (!list_empty(head)) {
-		ln = list_first_entry(head, struct line_node, list);
-		list_del(&ln->list);
-		free(ln);
-	}
-}
-
 /* Dwarf FL wrappers */
 static char *debuginfo_path;	/* Currently dummy */
 
@@ -880,7 +822,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
 }
 
 /* Find lines which match lazy pattern */
-static int find_lazy_match_lines(struct list_head *head,
+static int find_lazy_match_lines(struct intlist *list,
 				 const char *fname, const char *pat)
 {
 	FILE *fp;
@@ -901,7 +843,7 @@ static int find_lazy_match_lines(struct list_head *head,
 			line[len - 1] = '\0';
 
 		if (strlazymatch(line, pat)) {
-			line_list__add_line(head, linenum);
+			intlist__add(list, linenum);
 			count++;
 		}
 		linenum++;
@@ -924,7 +866,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
 	Dwarf_Die *sc_die, die_mem;
 	int ret;
 
-	if (!line_list__has_line(&pf->lcache, lineno) ||
+	if (!intlist__has_entry(pf->lcache, lineno) ||
 	    strtailcmp(fname, pf->fname) != 0)
 		return 0;
 
@@ -952,9 +894,9 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
 	int ret = 0;
 
-	if (list_empty(&pf->lcache)) {
+	if (intlist__empty(pf->lcache)) {
 		/* Matching lazy line pattern */
-		ret = find_lazy_match_lines(&pf->lcache, pf->fname,
+		ret = find_lazy_match_lines(pf->lcache, pf->fname,
 					    pf->pev->point.lazy_line);
 		if (ret <= 0)
 			return ret;
@@ -1096,7 +1038,9 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
 #endif
 
 	off = 0;
-	line_list__init(&pf->lcache);
+	pf->lcache = intlist__new(NULL);
+	if (!pf->lcache)
+		return -ENOMEM;
 
 	/* Fastpath: lookup by function name from .debug_pubnames section */
 	if (pp->function) {
@@ -1149,7 +1093,8 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
 	}
 
 found:
-	line_list__free(&pf->lcache);
+	intlist__delete(pf->lcache);
+	pf->lcache = NULL;
 
 	return ret;
 }
@@ -1537,7 +1482,7 @@ static int line_range_add_line(const char *src, unsigned int lineno,
 		if (lr->path == NULL)
 			return -ENOMEM;
 	}
-	return line_list__add_line(&lr->line_list, lineno);
+	return intlist__add(lr->line_list, lineno);
 }
 
 static int line_range_walk_cb(const char *fname, int lineno,
@@ -1565,7 +1510,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 
 	/* Update status */
 	if (ret >= 0)
-		if (!list_empty(&lf->lr->line_list))
+		if (!intlist__empty(lf->lr->line_list))
 			ret = lf->found = 1;
 		else
 			ret = 0;	/* Lines are not found */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index ffc33cd..592c4da 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include "util.h"
+#include "intlist.h"
 #include "probe-event.h"
 
 #define MAX_PROBE_BUFFER	1024
@@ -66,7 +67,7 @@ struct probe_finder {
 	const char		*fname;		/* Real file name */
 	Dwarf_Die		cu_die;		/* Current CU */
 	Dwarf_Die		sp_die;
-	struct list_head	lcache;		/* Line cache for lazy match */
+	struct intlist		*lcache;	/* Line cache for lazy match */
 
 	/* For variable searching */
 #if _ELFUTILS_PREREQ(0, 142)

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

* [tip:perf/core] perf probe: Unify show_available_functions for uprobes/kprobes
  2014-02-06  5:32 ` [PATCH -tip v3 04/11] [CLEANUP] perf-probe: Unify show_available_functions for uprobes/kprobes Masami Hiramatsu
@ 2014-02-22 18:00   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 29+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2014-02-22 18:00 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, mingo, dave.long, hpa, mingo, namhyung,
	masami.hiramatsu.pt, rostedt, srikar, dsahern, oleg, tglx

Commit-ID:  2df58634cd2ad33d7c7ca2e02e1a44db6c8cf68d
Gitweb:     http://git.kernel.org/tip/2df58634cd2ad33d7c7ca2e02e1a44db6c8cf68d
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 6 Feb 2014 05:32:11 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 18 Feb 2014 09:34:50 -0300

perf probe: Unify show_available_functions for uprobes/kprobes

Unify show_available_functions for uprobes/kprobes to cleanup and reduce
the code. This also improves error messages.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: "David A. Long" <dave.long@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20140206053211.29635.20563.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-event.c | 72 ++++++++++++++++---------------------------
 1 file changed, 26 insertions(+), 46 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f70fd08..ace3ba3 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2323,66 +2323,46 @@ static int filter_available_functions(struct map *map __maybe_unused,
 	return 1;
 }
 
-static int __show_available_funcs(struct map *map)
-{
-	if (map__load(map, filter_available_functions)) {
-		pr_err("Failed to load map.\n");
-		return -EINVAL;
-	}
-	if (!dso__sorted_by_name(map->dso, map->type))
-		dso__sort_by_name(map->dso, map->type);
-
-	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
-	return 0;
-}
-
-static int available_kernel_funcs(const char *module)
+int show_available_funcs(const char *target, struct strfilter *_filter,
+					bool user)
 {
 	struct map *map;
 	int ret;
 
-	ret = init_symbol_maps(false);
+	ret = init_symbol_maps(user);
 	if (ret < 0)
 		return ret;
 
-	map = kernel_get_module_map(module);
+	/* Get a symbol map */
+	if (user)
+		map = dso__new_map(target);
+	else
+		map = kernel_get_module_map(target);
 	if (!map) {
-		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
+		pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
 		return -EINVAL;
 	}
-	ret = __show_available_funcs(map);
-	exit_symbol_maps();
-
-	return ret;
-}
-
-static int available_user_funcs(const char *target)
-{
-	struct map *map;
-	int ret;
 
-	ret = init_symbol_maps(true);
-	if (ret < 0)
-		return ret;
-
-	map = dso__new_map(target);
-	ret = __show_available_funcs(map);
-	dso__delete(map->dso);
-	map__delete(map);
-	exit_symbol_maps();
-	return ret;
-}
-
-int show_available_funcs(const char *target, struct strfilter *_filter,
-					bool user)
-{
-	setup_pager();
+	/* Load symbols with given filter */
 	available_func_filter = _filter;
+	if (map__load(map, filter_available_functions)) {
+		pr_err("Failed to load symbols in %s\n", (target) ? : "kernel");
+		goto end;
+	}
+	if (!dso__sorted_by_name(map->dso, map->type))
+		dso__sort_by_name(map->dso, map->type);
 
-	if (!user)
-		return available_kernel_funcs(target);
+	/* Show all (filtered) symbols */
+	setup_pager();
+	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+end:
+	if (user) {
+		dso__delete(map->dso);
+		map__delete(map);
+	}
+	exit_symbol_maps();
 
-	return available_user_funcs(target);
+	return ret;
 }
 
 /*

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

* [tip:perf/core] perf probe: Show in what binaries/ modules probes are set
  2014-02-06  5:32 ` [PATCH -tip v3 05/11] perf-probe: Show in what binaries/modules probes are set Masami Hiramatsu
@ 2014-02-22 18:00   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 29+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2014-02-22 18:00 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, mingo, dave.long, hpa, mingo, namhyung,
	masami.hiramatsu.pt, rostedt, srikar, dsahern, oleg, tglx

Commit-ID:  fb226ccd2a6f77be13009edc196da2077800066b
Gitweb:     http://git.kernel.org/tip/fb226ccd2a6f77be13009edc196da2077800066b
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 6 Feb 2014 05:32:13 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 18 Feb 2014 09:34:50 -0300

perf probe: Show in what binaries/modules probes are set

Show the name of binary file or modules in which the probes are set with
--list option.

Without this change;

  # ./perf probe -m drm drm_av_sync_delay
  # ./perf probe -x perf dso__load_vmlinux

  # ./perf probe -l
    probe:drm_av_sync_delay (on drm_av_sync_delay)
    probe_perf:dso__load_vmlinux (on 0x000000000006d110)

With this change;

  # ./perf probe -l
    probe:drm_av_sync_delay (on drm_av_sync_delay in drm)
    probe_perf:dso__load_vmlinux (on 0x000000000006d110 in /kbuild/ksrc/linux-3/tools/perf/perf)

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: "David A. Long" <dave.long@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20140206053213.29635.69948.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-event.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index ace3ba3..de9fe90 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1728,7 +1728,8 @@ static struct strlist *get_probe_trace_command_rawlist(int fd)
 }
 
 /* Show an event */
-static int show_perf_probe_event(struct perf_probe_event *pev)
+static int show_perf_probe_event(struct perf_probe_event *pev,
+				 const char *module)
 {
 	int i, ret;
 	char buf[128];
@@ -1744,6 +1745,8 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
 		return ret;
 
 	printf("  %-20s (on %s", buf, place);
+	if (module)
+		printf(" in %s", module);
 
 	if (pev->nargs > 0) {
 		printf(" with");
@@ -1781,7 +1784,8 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
 			ret = convert_to_perf_probe_event(&tev, &pev,
 								is_kprobe);
 			if (ret >= 0)
-				ret = show_perf_probe_event(&pev);
+				ret = show_perf_probe_event(&pev,
+							    tev.point.module);
 		}
 		clear_perf_probe_event(&pev);
 		clear_probe_trace_event(&tev);
@@ -1980,7 +1984,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 		group = pev->group;
 		pev->event = tev->event;
 		pev->group = tev->group;
-		show_perf_probe_event(pev);
+		show_perf_probe_event(pev, tev->point.module);
 		/* Trick here - restore current event/group */
 		pev->event = (char *)event;
 		pev->group = (char *)group;

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

* [tip:perf/core] perf probe: Use ref_reloc_sym based address instead of the symbol name
  2014-02-06  5:32 ` [PATCH -tip v3 06/11] perf-probe: Use ref_reloc_sym based address instead of the symbol name Masami Hiramatsu
@ 2014-02-22 18:00   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 29+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2014-02-22 18:00 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, mingo, dave.long, hpa, mingo, namhyung,
	masami.hiramatsu.pt, rostedt, srikar, dsahern, oleg, tglx

Commit-ID:  dfef99cd0b2c8abafb571e5992ce954135be5f40
Gitweb:     http://git.kernel.org/tip/dfef99cd0b2c8abafb571e5992ce954135be5f40
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 6 Feb 2014 05:32:16 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 18 Feb 2014 09:34:51 -0300

perf probe: Use ref_reloc_sym based address instead of the symbol name

Since several local symbols can have same name (e.g. t_show), we need to
use the relative address from the symbol referred by kmap->ref_reloc_sym
instead of the target symbol name itself.

Because the kernel address space layout randomize (kASLR) changes the
absolute address of kernel symbols, we can't rely on the absolute
address.

Note that this works only with debuginfo.

E.g. without this change;
  ----
  # ./perf probe -a "t_show \$vars"
  Added new events:
    probe:t_show         (on t_show with $vars)
    probe:t_show_1       (on t_show with $vars)
    probe:t_show_2       (on t_show with $vars)
    probe:t_show_3       (on t_show with $vars)

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

          perf record -e probe:t_show_3 -aR sleep 1
  ----
OK, we have 4 different t_show()s. All functions have
different arguments as below;
  ----
  # cat /sys/kernel/debug/tracing/kprobe_events
  p:probe/t_show t_show m=%di:u64 v=%si:u64
  p:probe/t_show_1 t_show m=%di:u64 v=%si:u64 t=%si:u64
  p:probe/t_show_2 t_show m=%di:u64 v=%si:u64 fmt=%si:u64
  p:probe/t_show_3 t_show m=%di:u64 v=%si:u64 file=%si:u64
  ----
However, all of them have been put on the *same* address.
  ----
  # cat /sys/kernel/debug/kprobes/list
  ffffffff810d9720  k  t_show+0x0    [DISABLED]
  ffffffff810d9720  k  t_show+0x0    [DISABLED]
  ffffffff810d9720  k  t_show+0x0    [DISABLED]
  ffffffff810d9720  k  t_show+0x0    [DISABLED]
  ----

With this change;
  ----
  # ./perf probe -a "t_show \$vars"
  Added new events:
    probe:t_show         (on t_show with $vars)
    probe:t_show_1       (on t_show with $vars)
    probe:t_show_2       (on t_show with $vars)
    probe:t_show_3       (on t_show with $vars)

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

          perf record -e probe:t_show_3 -aR sleep 1

  # cat /sys/kernel/debug/tracing/kprobe_events
  p:probe/t_show _stext+889880 m=%di:u64 v=%si:u64
  p:probe/t_show_1 _stext+928568 m=%di:u64 v=%si:u64 t=%si:u64
  p:probe/t_show_2 _stext+969512 m=%di:u64 v=%si:u64 fmt=%si:u64
  p:probe/t_show_3 _stext+1001416 m=%di:u64 v=%si:u64 file=%si:u64

  # cat /sys/kernel/debug/kprobes/list
  ffffffffb50d95e0  k  t_show+0x0    [DISABLED]
  ffffffffb50e2d00  k  t_show+0x0    [DISABLED]
  ffffffffb50f4990  k  t_show+0x0    [DISABLED]
  ffffffffb50eccf0  k  t_show+0x0    [DISABLED]
  ----
This time, each event is put in different address
correctly.

Note that currently this doesn't support address-based
probe on modules (thus the probes on modules are symbol
based), since it requires relative address probe syntax
for kprobe-tracer, and it isn't implemented yet.

One more note, this allows us to put events on correct
address, but --list option should be updated to show
correct corresponding source code.

Changes from v2:
  - Refer kmap->ref_reloc_sym instead of "_stext".
  - Refer map->reloc to catch up the kASLR perf fix.

Changes from v1:
  - Use _stext relative address instead of actual
    absolute address recorded in debuginfo.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: "David A. Long" <dave.long@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20140206053216.29635.22584.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-event.c | 58 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 49 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index de9fe90..1ce2cb9 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -383,6 +383,51 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
 	return ret;
 }
 
+static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
+{
+	/* kmap->ref_reloc_sym should be set if host_machine is initialized */
+	struct kmap *kmap;
+
+	kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
+	return kmap->ref_reloc_sym;
+}
+
+/* Post processing the probe events */
+static int post_process_probe_trace_events(struct probe_trace_event *tevs,
+					   int ntevs, const char *module,
+					   bool uprobe)
+{
+	struct ref_reloc_sym *reloc_sym;
+	char *tmp;
+	int i;
+
+	if (uprobe)
+		return add_exec_to_probe_trace_events(tevs, ntevs, module);
+
+	/* Note that currently ref_reloc_sym based probe is not for drivers */
+	if (module)
+		return add_module_to_probe_trace_events(tevs, ntevs, module);
+
+	reloc_sym = __kernel_get_ref_reloc_sym();
+	if (!reloc_sym) {
+		pr_warning("Relocated base symbol is not found!\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ntevs; i++) {
+		if (tevs[i].point.address) {
+			tmp = strdup(reloc_sym->name);
+			if (!tmp)
+				return -ENOMEM;
+			free(tevs[i].point.symbol);
+			tevs[i].point.symbol = tmp;
+			tevs[i].point.offset = tevs[i].point.address -
+					       reloc_sym->unrelocated_addr;
+		}
+	}
+	return 0;
+}
+
 static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
 {
 	int i;
@@ -411,21 +456,16 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 		return 0;
 	}
 
+	pr_debug("Try to find probe point from debuginfo.\n");
 	/* Searching trace events corresponding to a probe event */
 	ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs);
 
 	debuginfo__delete(dinfo);
 
 	if (ntevs > 0) {	/* Succeeded to find trace events */
-		pr_debug("find %d probe_trace_events.\n", ntevs);
-		if (target) {
-			if (pev->uprobes)
-				ret = add_exec_to_probe_trace_events(*tevs,
-						 ntevs, target);
-			else
-				ret = add_module_to_probe_trace_events(*tevs,
-						 ntevs, target);
-		}
+		pr_debug("Found %d probe_trace_events.\n", ntevs);
+		ret = post_process_probe_trace_events(*tevs, ntevs,
+							target, pev->uprobes);
 		if (ret < 0) {
 			clear_probe_trace_events(*tevs, ntevs);
 			zfree(tevs);

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

* [tip:perf/core] perf probe: Find given address from offline dwarf
  2014-02-06  5:32 ` [PATCH -tip v3 07/11] perf-probe: Find given address from offline dwarf Masami Hiramatsu
@ 2014-02-22 18:00   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 29+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2014-02-22 18:00 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, mingo, dave.long, hpa, mingo, namhyung,
	masami.hiramatsu.pt, rostedt, srikar, dsahern, oleg, tglx

Commit-ID:  f90acac75713cc6f18a4b2f1b9162bc1cd893c20
Gitweb:     http://git.kernel.org/tip/f90acac75713cc6f18a4b2f1b9162bc1cd893c20
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 6 Feb 2014 05:32:18 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 18 Feb 2014 09:34:51 -0300

perf probe: Find given address from offline dwarf

Find the given address from offline dwarfs instead of online kernel
dwarfs.

On the KASLR enabled kernel, the kernel text section is loaded with
random offset, and the debuginfo__new_online_kernel can't handle it. So
let's move to the offline dwarf loader instead of using the online dwarf
loader.

As a result, since we don't need debuginfo__new_online_kernel any more,
this also removes the functions related to that.

Without this change;

  # ./perf probe -l
    probe:t_show         (on _stext+901288 with m v)
    probe:t_show_1       (on _stext+939624 with m v t)
    probe:t_show_2       (on _stext+980296 with m v fmt)
    probe:t_show_3       (on _stext+1014392 with m v file)

With this change;

  # ./perf probe -l
    probe:t_show         (on t_show@linux-3/kernel/trace/ftrace.c with m v)
    probe:t_show_1       (on t_show@linux-3/kernel/trace/trace.c with m v t)
    probe:t_show_2       (on t_show@kernel/trace/trace_printk.c with m v fmt)
    probe:t_show_3       (on t_show@kernel/trace/trace_events.c with m v file)

Changes from v2:
 - Instead of retrying, directly opens offline dwarf.
 - Remove debuginfo__new_online_kernel and related functions.
 - Refer map->reloc to get the correct address of a symbol.
 - Add a special case for handling ref_reloc_sym based address.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: "David A. Long" <dave.long@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20140206053218.29635.74821.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-event.c  | 40 +++++++++++++-------
 tools/perf/util/probe-finder.c | 86 ------------------------------------------
 tools/perf/util/probe-finder.h |  1 -
 3 files changed, 26 insertions(+), 101 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1ce2cb9..8e34c8d 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -248,6 +248,18 @@ static struct debuginfo *open_debuginfo(const char *module)
 	return debuginfo__new(path);
 }
 
+static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
+{
+	/* kmap->ref_reloc_sym should be set if host_machine is initialized */
+	struct kmap *kmap;
+
+	if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0)
+		return NULL;
+
+	kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
+	return kmap->ref_reloc_sym;
+}
+
 /*
  * Convert trace point to probe point with debuginfo
  * Currently only handles kprobes.
@@ -256,18 +268,27 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 					struct perf_probe_point *pp)
 {
 	struct symbol *sym;
+	struct ref_reloc_sym *reloc_sym;
 	struct map *map;
-	u64 addr;
+	u64 addr = 0;
 	int ret = -ENOENT;
 	struct debuginfo *dinfo;
 
-	sym = __find_kernel_function_by_name(tp->symbol, &map);
-	if (sym) {
-		addr = map->unmap_ip(map, sym->start + tp->offset);
+	/* ref_reloc_sym is just a label. Need a special fix*/
+	reloc_sym = __kernel_get_ref_reloc_sym();
+	if (reloc_sym && strcmp(tp->symbol, reloc_sym->name) == 0)
+		addr = reloc_sym->unrelocated_addr + tp->offset;
+	else {
+		sym = __find_kernel_function_by_name(tp->symbol, &map);
+		if (sym)
+			addr = map->unmap_ip(map, sym->start + tp->offset) -
+				map->reloc;
+	}
+	if (addr) {
 		pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
 			 tp->offset, addr);
 
-		dinfo = debuginfo__new_online_kernel(addr);
+		dinfo = open_debuginfo(tp->module);
 		if (dinfo) {
 			ret = debuginfo__find_probe_point(dinfo,
 						 (unsigned long)addr, pp);
@@ -383,15 +404,6 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
 	return ret;
 }
 
-static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
-{
-	/* kmap->ref_reloc_sym should be set if host_machine is initialized */
-	struct kmap *kmap;
-
-	kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
-	return kmap->ref_reloc_sym;
-}
-
 /* Post processing the probe events */
 static int post_process_probe_trace_events(struct probe_trace_event *tevs,
 					   int ntevs, const char *module,
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index e5e589f..4f6e277 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -89,79 +89,6 @@ error:
 	return -ENOENT;
 }
 
-#if _ELFUTILS_PREREQ(0, 148)
-/* This method is buggy if elfutils is older than 0.148 */
-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);
-
-	pr_debug2("Use file %s for %s\n", 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 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 live kernel image */
-static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
-					       Dwarf_Addr addr)
-{
-	dbg->dwfl = dwfl_begin(&kernel_callbacks);
-	if (!dbg->dwfl)
-		return -EINVAL;
-
-	/* Load the kernel dwarves: Don't care the result here */
-	dwfl_linux_kernel_report_kernel(dbg->dwfl);
-	dwfl_linux_kernel_report_modules(dbg->dwfl);
-
-	dbg->dbg = dwfl_addrdwarf(dbg->dwfl, addr, &dbg->bias);
-	/* Here, check whether we could get a real dwarf */
-	if (!dbg->dbg) {
-		pr_debug("Failed to find kernel dwarf at %lx\n",
-			 (unsigned long)addr);
-		dwfl_end(dbg->dwfl);
-		memset(dbg, 0, sizeof(*dbg));
-		return -ENOENT;
-	}
-
-	return 0;
-}
-#else
-/* With older elfutils, this just support kernel module... */
-static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
-					       Dwarf_Addr addr __maybe_unused)
-{
-	const char *path = kernel_get_module_path("kernel");
-
-	if (!path) {
-		pr_err("Failed to find vmlinux path\n");
-		return -ENOENT;
-	}
-
-	pr_debug2("Use file %s for debuginfo\n", path);
-	return debuginfo__init_offline_dwarf(dbg, path);
-}
-#endif
-
 struct debuginfo *debuginfo__new(const char *path)
 {
 	struct debuginfo *dbg = zalloc(sizeof(*dbg));
@@ -174,19 +101,6 @@ struct debuginfo *debuginfo__new(const char *path)
 	return dbg;
 }
 
-struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
-{
-	struct debuginfo *dbg = zalloc(sizeof(*dbg));
-
-	if (!dbg)
-		return NULL;
-
-	if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0)
-		zfree(&dbg);
-
-	return dbg;
-}
-
 void debuginfo__delete(struct debuginfo *dbg)
 {
 	if (dbg) {
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 592c4da..3fc5973 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -31,7 +31,6 @@ struct debuginfo {
 };
 
 extern struct debuginfo *debuginfo__new(const char *path);
-extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr);
 extern void debuginfo__delete(struct debuginfo *dbg);
 
 /* Find probe_trace_events specified by perf_probe_event from debuginfo */

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

* [tip:perf/core] perf probe: Show appropriate symbol for ref_reloc_sym based kprobes
  2014-02-06  5:32 ` [PATCH -tip v3 08/11] perf-probe: Show appropriate symbol for ref_reloc_sym based kprobes Masami Hiramatsu
@ 2014-02-22 18:01   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 29+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2014-02-22 18:01 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, mingo, dave.long, hpa, mingo, namhyung,
	masami.hiramatsu.pt, rostedt, srikar, dsahern, oleg, tglx

Commit-ID:  8f33f7deac485a61f38aa690b85489322a4d958e
Gitweb:     http://git.kernel.org/tip/8f33f7deac485a61f38aa690b85489322a4d958e
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 6 Feb 2014 05:32:20 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 18 Feb 2014 09:34:51 -0300

perf probe: Show appropriate symbol for ref_reloc_sym based kprobes

Show appropriate symbol for ref_reloc_sym based kprobes instead of
refpoint+offset when perf-probe -l runs without debuginfo.

Without this change:
  # ./perf probe -l
    probe:t_show         (on _stext+889880 with m v)
    probe:t_show_1       (on _stext+928568 with m v t)
    probe:t_show_2       (on _stext+969512 with m v fmt)
    probe:t_show_3       (on _stext+1001416 with m v file)

With this change:
  # ./perf probe -l
    probe:t_show         (on t_show with m v)
    probe:t_show_1       (on t_show with m v t)
    probe:t_show_2       (on t_show with m v fmt)
    probe:t_show_3       (on t_show with m v file)

Changes from v2:
 - Check ref_reloc_sym to find correct unrelocated address.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: "David A. Long" <dave.long@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20140206053220.29635.81819.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-event.c | 83 ++++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 28 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8e34c8d..f86820c 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -121,6 +121,42 @@ static struct symbol *__find_kernel_function_by_name(const char *name,
 						     NULL);
 }
 
+static struct symbol *__find_kernel_function(u64 addr, struct map **mapp)
+{
+	return machine__find_kernel_function(host_machine, addr, mapp, NULL);
+}
+
+static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void)
+{
+	/* kmap->ref_reloc_sym should be set if host_machine is initialized */
+	struct kmap *kmap;
+
+	if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0)
+		return NULL;
+
+	kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
+	return kmap->ref_reloc_sym;
+}
+
+static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc)
+{
+	struct ref_reloc_sym *reloc_sym;
+	struct symbol *sym;
+	struct map *map;
+
+	/* ref_reloc_sym is just a label. Need a special fix*/
+	reloc_sym = kernel_get_ref_reloc_sym();
+	if (reloc_sym && strcmp(name, reloc_sym->name) == 0)
+		return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr;
+	else {
+		sym = __find_kernel_function_by_name(name, &map);
+		if (sym)
+			return map->unmap_ip(map, sym->start) -
+				(reloc) ? 0 : map->reloc;
+	}
+	return 0;
+}
+
 static struct map *kernel_get_module_map(const char *module)
 {
 	struct rb_node *nd;
@@ -216,12 +252,26 @@ out:
 static int convert_to_perf_probe_point(struct probe_trace_point *tp,
 					struct perf_probe_point *pp)
 {
-	pp->function = strdup(tp->symbol);
+	struct symbol *sym;
+	struct map *map;
+	u64 addr = kernel_get_symbol_address_by_name(tp->symbol, true);
+
+	if (addr) {
+		addr += tp->offset;
+		sym = __find_kernel_function(addr, &map);
+		if (!sym)
+			goto failed;
+		pp->function = strdup(sym->name);
+		pp->offset = addr - map->unmap_ip(map, sym->start);
+	} else {
+failed:
+		pp->function = strdup(tp->symbol);
+		pp->offset = tp->offset;
+	}
 
 	if (pp->function == NULL)
 		return -ENOMEM;
 
-	pp->offset = tp->offset;
 	pp->retprobe = tp->retprobe;
 
 	return 0;
@@ -248,18 +298,6 @@ static struct debuginfo *open_debuginfo(const char *module)
 	return debuginfo__new(path);
 }
 
-static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
-{
-	/* kmap->ref_reloc_sym should be set if host_machine is initialized */
-	struct kmap *kmap;
-
-	if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0)
-		return NULL;
-
-	kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
-	return kmap->ref_reloc_sym;
-}
-
 /*
  * Convert trace point to probe point with debuginfo
  * Currently only handles kprobes.
@@ -267,24 +305,13 @@ static struct ref_reloc_sym *__kernel_get_ref_reloc_sym(void)
 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 					struct perf_probe_point *pp)
 {
-	struct symbol *sym;
-	struct ref_reloc_sym *reloc_sym;
-	struct map *map;
 	u64 addr = 0;
 	int ret = -ENOENT;
 	struct debuginfo *dinfo;
 
-	/* ref_reloc_sym is just a label. Need a special fix*/
-	reloc_sym = __kernel_get_ref_reloc_sym();
-	if (reloc_sym && strcmp(tp->symbol, reloc_sym->name) == 0)
-		addr = reloc_sym->unrelocated_addr + tp->offset;
-	else {
-		sym = __find_kernel_function_by_name(tp->symbol, &map);
-		if (sym)
-			addr = map->unmap_ip(map, sym->start + tp->offset) -
-				map->reloc;
-	}
+	addr = kernel_get_symbol_address_by_name(tp->symbol, false);
 	if (addr) {
+		addr += tp->offset;
 		pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
 			 tp->offset, addr);
 
@@ -420,7 +447,7 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs,
 	if (module)
 		return add_module_to_probe_trace_events(tevs, ntevs, module);
 
-	reloc_sym = __kernel_get_ref_reloc_sym();
+	reloc_sym = kernel_get_ref_reloc_sym();
 	if (!reloc_sym) {
 		pr_warning("Relocated base symbol is not found!\n");
 		return -EINVAL;

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

* [tip:perf/core] perf probe: Show source-level or symbol-level info for uprobes
  2014-02-06  5:32 ` [PATCH -tip v3 09/11] perf-probe: Show source-level or symbol-level info for uprobes Masami Hiramatsu
@ 2014-02-22 18:01   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 29+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2014-02-22 18:01 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, mingo, dave.long, hpa, mingo, namhyung,
	masami.hiramatsu.pt, rostedt, srikar, dsahern, oleg, tglx

Commit-ID:  5a6f63145491f905de1c5c6c46c5cd62c004d0d1
Gitweb:     http://git.kernel.org/tip/5a6f63145491f905de1c5c6c46c5cd62c004d0d1
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 6 Feb 2014 05:32:23 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 18 Feb 2014 09:34:51 -0300

perf probe: Show source-level or symbol-level info for uprobes

Show source-level or symbol-level information for uprobe events.

Without this change;
  # ./perf probe -l
    probe_perf:dso__load_vmlinux (on 0x000000000006d110 in /kbuild/ksrc/linux-3/tools/perf/perf)

With this change;
  # ./perf probe -l
    probe_perf:dso__load_vmlinux (on dso__load_vmlinux@util/symbol.c in /kbuild/ksrc/linux-3/tools/perf/perf)

Changes from v2:
 - Update according to previous patches.

Changes from v1:
 - Rewrite the code based on new series.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: "David A. Long" <dave.long@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20140206053223.29635.51280.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-event.c | 227 +++++++++++++++++++++++++++---------------
 1 file changed, 144 insertions(+), 83 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f86820c..3c35b7a 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -249,34 +249,6 @@ out:
 	return ret;
 }
 
-static int convert_to_perf_probe_point(struct probe_trace_point *tp,
-					struct perf_probe_point *pp)
-{
-	struct symbol *sym;
-	struct map *map;
-	u64 addr = kernel_get_symbol_address_by_name(tp->symbol, true);
-
-	if (addr) {
-		addr += tp->offset;
-		sym = __find_kernel_function(addr, &map);
-		if (!sym)
-			goto failed;
-		pp->function = strdup(sym->name);
-		pp->offset = addr - map->unmap_ip(map, sym->start);
-	} else {
-failed:
-		pp->function = strdup(tp->symbol);
-		pp->offset = tp->offset;
-	}
-
-	if (pp->function == NULL)
-		return -ENOMEM;
-
-	pp->retprobe = tp->retprobe;
-
-	return 0;
-}
-
 #ifdef HAVE_DWARF_SUPPORT
 /* Open new debuginfo of given module */
 static struct debuginfo *open_debuginfo(const char *module)
@@ -298,44 +270,6 @@ static struct debuginfo *open_debuginfo(const char *module)
 	return debuginfo__new(path);
 }
 
-/*
- * Convert trace point to probe point with debuginfo
- * Currently only handles kprobes.
- */
-static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-					struct perf_probe_point *pp)
-{
-	u64 addr = 0;
-	int ret = -ENOENT;
-	struct debuginfo *dinfo;
-
-	addr = kernel_get_symbol_address_by_name(tp->symbol, false);
-	if (addr) {
-		addr += tp->offset;
-		pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
-			 tp->offset, addr);
-
-		dinfo = open_debuginfo(tp->module);
-		if (dinfo) {
-			ret = debuginfo__find_probe_point(dinfo,
-						 (unsigned long)addr, pp);
-			debuginfo__delete(dinfo);
-		} else {
-			pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n",
-				 addr);
-			ret = -ENOENT;
-		}
-	}
-	if (ret <= 0) {
-		pr_debug("Failed to find corresponding probes from "
-			 "debuginfo. Use kprobe event information.\n");
-		return convert_to_perf_probe_point(tp, pp);
-	}
-	pp->retprobe = tp->retprobe;
-
-	return 0;
-}
-
 static int get_text_start_address(const char *exec, unsigned long *address)
 {
 	Elf *elf;
@@ -364,6 +298,57 @@ out:
 	return ret;
 }
 
+/*
+ * Convert trace point to probe point with debuginfo
+ */
+static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
+					    struct perf_probe_point *pp,
+					    bool is_kprobe)
+{
+	struct debuginfo *dinfo = NULL;
+	unsigned long stext = 0;
+	u64 addr = tp->address;
+	int ret = -ENOENT;
+
+	/* convert the address to dwarf address */
+	if (!is_kprobe) {
+		if (!addr) {
+			ret = -EINVAL;
+			goto error;
+		}
+		ret = get_text_start_address(tp->module, &stext);
+		if (ret < 0)
+			goto error;
+		addr += stext;
+	} else {
+		addr = kernel_get_symbol_address_by_name(tp->symbol, false);
+		if (addr == 0)
+			goto error;
+		addr += tp->offset;
+	}
+
+	pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
+		 tp->module ? : "kernel");
+
+	dinfo = open_debuginfo(tp->module);
+	if (dinfo) {
+		ret = debuginfo__find_probe_point(dinfo,
+						 (unsigned long)addr, pp);
+		debuginfo__delete(dinfo);
+	} else {
+		pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr);
+		ret = -ENOENT;
+	}
+
+	if (ret > 0) {
+		pp->retprobe = tp->retprobe;
+		return 0;
+	}
+error:
+	pr_debug("Failed to find corresponding probes from debuginfo.\n");
+	return ret ? : -ENOENT;
+}
+
 static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
 					  int ntevs, const char *exec)
 {
@@ -815,10 +800,12 @@ out:
 
 #else	/* !HAVE_DWARF_SUPPORT */
 
-static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-					struct perf_probe_point *pp)
+static int
+find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused,
+				 struct perf_probe_point *pp __maybe_unused,
+				 bool is_kprobe __maybe_unused)
 {
-	return convert_to_perf_probe_point(tp, pp);
+	return -ENOSYS;
 }
 
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
@@ -1343,16 +1330,21 @@ static int parse_probe_trace_command(const char *cmd,
 	} else
 		p = argv[1];
 	fmt1_str = strtok_r(p, "+", &fmt);
-	tp->symbol = strdup(fmt1_str);
-	if (tp->symbol == NULL) {
-		ret = -ENOMEM;
-		goto out;
+	if (fmt1_str[0] == '0')	/* only the address started with 0x */
+		tp->address = strtoul(fmt1_str, NULL, 0);
+	else {
+		/* Only the symbol-based probe has offset */
+		tp->symbol = strdup(fmt1_str);
+		if (tp->symbol == NULL) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		fmt2_str = strtok_r(NULL, "", &fmt);
+		if (fmt2_str == NULL)
+			tp->offset = 0;
+		else
+			tp->offset = strtoul(fmt2_str, NULL, 10);
 	}
-	fmt2_str = strtok_r(NULL, "", &fmt);
-	if (fmt2_str == NULL)
-		tp->offset = 0;
-	else
-		tp->offset = strtoul(fmt2_str, NULL, 10);
 
 	tev->nargs = argc - 2;
 	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
@@ -1623,6 +1615,79 @@ error:
 	return NULL;
 }
 
+static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
+					  struct perf_probe_point *pp,
+					  bool is_kprobe)
+{
+	struct symbol *sym = NULL;
+	struct map *map;
+	u64 addr;
+	int ret = -ENOENT;
+
+	if (!is_kprobe) {
+		map = dso__new_map(tp->module);
+		if (!map)
+			goto out;
+		addr = tp->address;
+		sym = map__find_symbol(map, addr, NULL);
+	} else {
+		addr = kernel_get_symbol_address_by_name(tp->symbol, true);
+		if (addr) {
+			addr += tp->offset;
+			sym = __find_kernel_function(addr, &map);
+		}
+	}
+	if (!sym)
+		goto out;
+
+	pp->retprobe = tp->retprobe;
+	pp->offset = addr - map->unmap_ip(map, sym->start);
+	pp->function = strdup(sym->name);
+	ret = pp->function ? 0 : -ENOMEM;
+
+out:
+	if (map && !is_kprobe) {
+		dso__delete(map->dso);
+		map__delete(map);
+	}
+
+	return ret;
+}
+
+static int convert_to_perf_probe_point(struct probe_trace_point *tp,
+					struct perf_probe_point *pp,
+					bool is_kprobe)
+{
+	char buf[128];
+	int ret;
+
+	ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe);
+	if (!ret)
+		return 0;
+	ret = find_perf_probe_point_from_map(tp, pp, is_kprobe);
+	if (!ret)
+		return 0;
+
+	pr_debug("Failed to find probe point from both of dwarf and map.\n");
+
+	if (tp->symbol) {
+		pp->function = strdup(tp->symbol);
+		pp->offset = tp->offset;
+	} else if (!tp->module && !is_kprobe) {
+		ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address);
+		if (ret < 0)
+			return ret;
+		pp->function = strdup(buf);
+		pp->offset = 0;
+	}
+	if (pp->function == NULL)
+		return -ENOMEM;
+
+	pp->retprobe = tp->retprobe;
+
+	return 0;
+}
+
 static int convert_to_perf_probe_event(struct probe_trace_event *tev,
 			       struct perf_probe_event *pev, bool is_kprobe)
 {
@@ -1636,11 +1701,7 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
 		return -ENOMEM;
 
 	/* Convert trace_point to probe_point */
-	if (is_kprobe)
-		ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
-	else
-		ret = convert_to_perf_probe_point(&tev->point, &pev->point);
-
+	ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe);
 	if (ret < 0)
 		return ret;
 

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

* [tip:perf/core] perf probe: Allow to add events on the local functions
  2014-02-06  5:32 ` [PATCH -tip v3 10/11] perf-probe: Allow to add events on the local functions Masami Hiramatsu
@ 2014-02-22 18:01   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 29+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2014-02-22 18:01 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, mingo, dave.long, hpa, mingo, namhyung,
	masami.hiramatsu.pt, rostedt, srikar, dsahern, oleg, tglx

Commit-ID:  eb948e50831bc64e6bb2589be7575ed7c159a429
Gitweb:     http://git.kernel.org/tip/eb948e50831bc64e6bb2589be7575ed7c159a429
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 6 Feb 2014 05:32:25 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 18 Feb 2014 09:38:43 -0300

perf probe: Allow to add events on the local functions

Allow to add events on the local functions without debuginfo.
(With the debuginfo, we can add events even on inlined functions)
Currently, probing on local functions requires debuginfo to
locate actual address. It is also possible without debuginfo since
we have symbol maps.

Without this change;
  ----
  # ./perf probe -a t_show
  Added new event:
    probe:t_show         (on t_show)

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

          perf record -e probe:t_show -aR sleep 1

  # ./perf probe -x perf -a identity__map_ip
  no symbols found in /kbuild/ksrc/linux-3/tools/perf/perf, maybe install a debug package?
  Failed to load map.
    Error: Failed to add events. (-22)
  ----
As the above results, perf probe just put one event
on the first found symbol for kprobe event. Moreover,
for uprobe event, perf probe failed to find local
functions.

With this change;
  ----
  # ./perf probe -a t_show
  Added new events:
    probe:t_show         (on t_show)
    probe:t_show_1       (on t_show)
    probe:t_show_2       (on t_show)
    probe:t_show_3       (on t_show)

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

          perf record -e probe:t_show_3 -aR sleep 1

  # ./perf probe -x perf -a identity__map_ip
  Added new events:
    probe_perf:identity__map_ip (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
    probe_perf:identity__map_ip_1 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
    probe_perf:identity__map_ip_2 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)
    probe_perf:identity__map_ip_3 (on identity__map_ip in /kbuild/ksrc/linux-3/tools/perf/perf)

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

          perf record -e probe_perf:identity__map_ip_3 -aR sleep 1
  ----
Now we succeed to put events on every given local functions
for both kprobes and uprobes. :)

Note that this also introduces some symbol rbtree
iteration macros; symbols__for_each, dso__for_each_symbol,
and map__for_each_symbol. These are for walking through
the symbol list in a map.

Changes from v2:
  - Fix add_exec_to_probe_trace_events() not to convert address
    to tp->symbol any more.
  - Fix to set kernel probes based on ref_reloc_sym.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: "David A. Long" <dave.long@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20140206053225.29635.15026.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/dso.h         |  10 ++
 tools/perf/util/map.h         |  10 ++
 tools/perf/util/probe-event.c | 378 +++++++++++++++++++-----------------------
 tools/perf/util/symbol.h      |  11 ++
 4 files changed, 204 insertions(+), 205 deletions(-)

diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index cd7d6f0..ab06f1c 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -102,6 +102,16 @@ struct dso {
 	char		 name[0];
 };
 
+/* dso__for_each_symbol - iterate over the symbols of given type
+ *
+ * @dso: the 'struct dso *' in which symbols itereated
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @n: the 'struct rb_node *' to use as a temporary storage
+ * @type: the 'enum map_type' type of symbols
+ */
+#define dso__for_each_symbol(dso, pos, n, type)	\
+	symbols__for_each_entry(&(dso)->symbols[(type)], pos, n)
+
 static inline void dso__set_loaded(struct dso *dso, enum map_type type)
 {
 	dso->loaded |= (1 << type);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 257e513..f00f058 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -90,6 +90,16 @@ u64 map__objdump_2mem(struct map *map, u64 ip);
 
 struct symbol;
 
+/* map__for_each_symbol - iterate over the symbols in the given map
+ *
+ * @map: the 'struct map *' in which symbols itereated
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @n: the 'struct rb_node *' to use as a temporary storage
+ * Note: caller must ensure map->dso is not NULL (map is loaded).
+ */
+#define map__for_each_symbol(map, pos, n)	\
+	dso__for_each_symbol(map->dso, pos, n, map->type)
+
 typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
 
 void map__init(struct map *map, enum map_type type,
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 3c35b7a..42bec67 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -70,8 +70,6 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 }
 
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
-static int convert_name_to_addr(struct perf_probe_event *pev,
-				const char *exec);
 static void clear_probe_trace_event(struct probe_trace_event *tev);
 static struct machine *host_machine;
 
@@ -249,6 +247,14 @@ out:
 	return ret;
 }
 
+static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
+{
+	int i;
+
+	for (i = 0; i < ntevs; i++)
+		clear_probe_trace_event(tevs + i);
+}
+
 #ifdef HAVE_DWARF_SUPPORT
 /* Open new debuginfo of given module */
 static struct debuginfo *open_debuginfo(const char *module)
@@ -353,8 +359,7 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
 					  int ntevs, const char *exec)
 {
 	int i, ret = 0;
-	unsigned long offset, stext = 0;
-	char buf[32];
+	unsigned long stext = 0;
 
 	if (!exec)
 		return 0;
@@ -365,15 +370,9 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
 
 	for (i = 0; i < ntevs && ret >= 0; i++) {
 		/* point.address is the addres of point.symbol + point.offset */
-		offset = tevs[i].point.address - stext;
-		tevs[i].point.offset = 0;
-		zfree(&tevs[i].point.symbol);
-		ret = e_snprintf(buf, 32, "0x%lx", offset);
-		if (ret < 0)
-			break;
+		tevs[i].point.address -= stext;
 		tevs[i].point.module = strdup(exec);
-		tevs[i].point.symbol = strdup(buf);
-		if (!tevs[i].point.symbol || !tevs[i].point.module) {
+		if (!tevs[i].point.module) {
 			ret = -ENOMEM;
 			break;
 		}
@@ -452,14 +451,6 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs,
 	return 0;
 }
 
-static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
-{
-	int i;
-
-	for (i = 0; i < ntevs; i++)
-		clear_probe_trace_event(tevs + i);
-}
-
 /* 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,
@@ -1586,20 +1577,27 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
 	if (buf == NULL)
 		return NULL;
 
+	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
+			 tev->group, tev->event);
+	if (len <= 0)
+		goto error;
+
+	/* Uprobes must have tp->address and tp->module */
+	if (tev->uprobes && (!tp->address || !tp->module))
+		goto error;
+
+	/* Use the tp->address for uprobes */
 	if (tev->uprobes)
-		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
-				 tp->retprobe ? 'r' : 'p',
-				 tev->group, tev->event,
-				 tp->module, tp->symbol);
+		ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx",
+				 tp->module, tp->address);
 	else
-		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
-				 tp->retprobe ? 'r' : 'p',
-				 tev->group, tev->event,
+		ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu",
 				 tp->module ?: "", tp->module ? ":" : "",
 				 tp->symbol, tp->offset);
 
-	if (len <= 0)
+	if (ret <= 0)
 		goto error;
+	len += ret;
 
 	for (i = 0; i < tev->nargs; i++) {
 		ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
@@ -2150,113 +2148,175 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 	return ret;
 }
 
-static int convert_to_probe_trace_events(struct perf_probe_event *pev,
-					  struct probe_trace_event **tevs,
-					  int max_tevs, const char *target)
+static char *looking_function_name;
+static int num_matched_functions;
+
+static int probe_function_filter(struct map *map __maybe_unused,
+				      struct symbol *sym)
+{
+	if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
+	    strcmp(looking_function_name, sym->name) == 0) {
+		num_matched_functions++;
+		return 0;
+	}
+	return 1;
+}
+
+#define strdup_or_goto(str, label)	\
+	({ char *__p = strdup(str); if (!__p) goto label; __p; })
+
+/*
+ * Find probe function addresses from map.
+ * Return an error or the number of found probe_trace_event
+ */
+static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
+					    struct probe_trace_event **tevs,
+					    int max_tevs, const char *target)
 {
+	struct map *map = NULL;
+	struct kmap *kmap = NULL;
+	struct ref_reloc_sym *reloc_sym = NULL;
 	struct symbol *sym;
-	int ret, i;
+	struct rb_node *nd;
 	struct probe_trace_event *tev;
+	struct perf_probe_point *pp = &pev->point;
+	struct probe_trace_point *tp;
+	int ret, i;
 
-	if (pev->uprobes && !pev->group) {
-		/* Replace group name if not given */
-		ret = convert_exec_to_group(target, &pev->group);
-		if (ret != 0) {
-			pr_warning("Failed to make a group name.\n");
-			return ret;
-		}
+	/* Init maps of given executable or kernel */
+	if (pev->uprobes)
+		map = dso__new_map(target);
+	else
+		map = kernel_get_module_map(target);
+	if (!map) {
+		ret = -EINVAL;
+		goto out;
 	}
 
-	/* Convert perf_probe_event with debuginfo */
-	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
-	if (ret != 0)
-		return ret;	/* Found in debuginfo or got an error */
-
-	if (pev->uprobes) {
-		ret = convert_name_to_addr(pev, target);
-		if (ret < 0)
-			return ret;
+	/*
+	 * Load matched symbols: Since the different local symbols may have
+	 * same name but different addresses, this lists all the symbols.
+	 */
+	num_matched_functions = 0;
+	looking_function_name = pp->function;
+	ret = map__load(map, probe_function_filter);
+	if (ret || num_matched_functions == 0) {
+		pr_err("Failed to find symbol %s in %s\n", pp->function,
+			target ? : "kernel");
+		ret = -ENOENT;
+		goto out;
+	} else if (num_matched_functions > max_tevs) {
+		pr_err("Too many functions matched in %s\n",
+			target ? : "kernel");
+		ret = -E2BIG;
+		goto out;
 	}
 
-	/* Allocate trace event buffer */
-	tev = *tevs = zalloc(sizeof(struct probe_trace_event));
-	if (tev == NULL)
-		return -ENOMEM;
+	if (!pev->uprobes) {
+		kmap = map__kmap(map);
+		reloc_sym = kmap->ref_reloc_sym;
+		if (!reloc_sym) {
+			pr_warning("Relocated base symbol is not found!\n");
+			ret = -EINVAL;
+			goto out;
+		}
+	}
 
-	/* Copy parameters */
-	tev->point.symbol = strdup(pev->point.function);
-	if (tev->point.symbol == NULL) {
+	/* Setup result trace-probe-events */
+	*tevs = zalloc(sizeof(*tev) * num_matched_functions);
+	if (!*tevs) {
 		ret = -ENOMEM;
-		goto error;
+		goto out;
 	}
 
-	if (target) {
-		tev->point.module = strdup(target);
-		if (tev->point.module == NULL) {
-			ret = -ENOMEM;
-			goto error;
+	ret = 0;
+	map__for_each_symbol(map, sym, nd) {
+		tev = (*tevs) + ret;
+		tp = &tev->point;
+		if (ret == num_matched_functions) {
+			pr_warning("Too many symbols are listed. Skip it.\n");
+			break;
 		}
-	}
+		ret++;
 
-	tev->point.offset = pev->point.offset;
-	tev->point.retprobe = pev->point.retprobe;
-	tev->nargs = pev->nargs;
-	tev->uprobes = pev->uprobes;
-
-	if (tev->nargs) {
-		tev->args = zalloc(sizeof(struct probe_trace_arg)
-				   * tev->nargs);
-		if (tev->args == NULL) {
-			ret = -ENOMEM;
-			goto error;
+		if (pp->offset > sym->end - sym->start) {
+			pr_warning("Offset %ld is bigger than the size of %s\n",
+				   pp->offset, sym->name);
+			ret = -ENOENT;
+			goto err_out;
+		}
+		/* Add one probe point */
+		tp->address = map->unmap_ip(map, sym->start) + pp->offset;
+		if (reloc_sym) {
+			tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out);
+			tp->offset = tp->address - reloc_sym->addr;
+		} else {
+			tp->symbol = strdup_or_goto(sym->name, nomem_out);
+			tp->offset = pp->offset;
+		}
+		tp->retprobe = pp->retprobe;
+		if (target)
+			tev->point.module = strdup_or_goto(target, nomem_out);
+		tev->uprobes = pev->uprobes;
+		tev->nargs = pev->nargs;
+		if (tev->nargs) {
+			tev->args = zalloc(sizeof(struct probe_trace_arg) *
+					   tev->nargs);
+			if (tev->args == NULL)
+				goto nomem_out;
 		}
 		for (i = 0; i < tev->nargs; i++) {
-			if (pev->args[i].name) {
-				tev->args[i].name = strdup(pev->args[i].name);
-				if (tev->args[i].name == NULL) {
-					ret = -ENOMEM;
-					goto error;
-				}
-			}
-			tev->args[i].value = strdup(pev->args[i].var);
-			if (tev->args[i].value == NULL) {
-				ret = -ENOMEM;
-				goto error;
-			}
-			if (pev->args[i].type) {
-				tev->args[i].type = strdup(pev->args[i].type);
-				if (tev->args[i].type == NULL) {
-					ret = -ENOMEM;
-					goto error;
-				}
-			}
+			if (pev->args[i].name)
+				tev->args[i].name =
+					strdup_or_goto(pev->args[i].name,
+							nomem_out);
+
+			tev->args[i].value = strdup_or_goto(pev->args[i].var,
+							    nomem_out);
+			if (pev->args[i].type)
+				tev->args[i].type =
+					strdup_or_goto(pev->args[i].type,
+							nomem_out);
 		}
 	}
 
-	if (pev->uprobes)
-		return 1;
+out:
+	if (map && pev->uprobes) {
+		/* Only when using uprobe(exec) map needs to be released */
+		dso__delete(map->dso);
+		map__delete(map);
+	}
+	return ret;
 
-	/* Currently just checking function name from symbol map */
-	sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
-	if (!sym) {
-		pr_warning("Kernel symbol \'%s\' not found.\n",
-			   tev->point.symbol);
-		ret = -ENOENT;
-		goto error;
-	} else if (tev->point.offset > sym->end - sym->start) {
-		pr_warning("Offset specified is greater than size of %s\n",
-			   tev->point.symbol);
-		ret = -ENOENT;
-		goto error;
+nomem_out:
+	ret = -ENOMEM;
+err_out:
+	clear_probe_trace_events(*tevs, num_matched_functions);
+	zfree(tevs);
+	goto out;
+}
 
+static int convert_to_probe_trace_events(struct perf_probe_event *pev,
+					  struct probe_trace_event **tevs,
+					  int max_tevs, const char *target)
+{
+	int ret;
+
+	if (pev->uprobes && !pev->group) {
+		/* Replace group name if not given */
+		ret = convert_exec_to_group(target, &pev->group);
+		if (ret != 0) {
+			pr_warning("Failed to make a group name.\n");
+			return ret;
+		}
 	}
 
-	return 1;
-error:
-	clear_probe_trace_event(tev);
-	free(tev);
-	*tevs = NULL;
-	return ret;
+	/* Convert perf_probe_event with debuginfo */
+	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
+	if (ret != 0)
+		return ret;	/* Found in debuginfo or got an error */
+
+	return find_probe_trace_events_from_map(pev, tevs, max_tevs, target);
 }
 
 struct __event_package {
@@ -2461,7 +2521,7 @@ static struct strfilter *available_func_filter;
 static int filter_available_functions(struct map *map __maybe_unused,
 				      struct symbol *sym)
 {
-	if (sym->binding == STB_GLOBAL &&
+	if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
 	    strfilter__compare(available_func_filter, sym->name))
 		return 0;
 	return 1;
@@ -2509,95 +2569,3 @@ end:
 	return ret;
 }
 
-/*
- * uprobe_events only accepts address:
- * Convert function and any offset to address
- */
-static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
-{
-	struct perf_probe_point *pp = &pev->point;
-	struct symbol *sym;
-	struct map *map = NULL;
-	char *function = NULL;
-	int ret = -EINVAL;
-	unsigned long long vaddr = 0;
-
-	if (!pp->function) {
-		pr_warning("No function specified for uprobes");
-		goto out;
-	}
-
-	function = strdup(pp->function);
-	if (!function) {
-		pr_warning("Failed to allocate memory by strdup.\n");
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	map = dso__new_map(exec);
-	if (!map) {
-		pr_warning("Cannot find appropriate DSO for %s.\n", exec);
-		goto out;
-	}
-	available_func_filter = strfilter__new(function, NULL);
-	if (map__load(map, filter_available_functions)) {
-		pr_err("Failed to load map.\n");
-		goto out;
-	}
-
-	sym = map__find_symbol_by_name(map, function, NULL);
-	if (!sym) {
-		pr_warning("Cannot find %s in DSO %s\n", function, exec);
-		goto out;
-	}
-
-	if (map->start > sym->start)
-		vaddr = map->start;
-	vaddr += sym->start + pp->offset + map->pgoff;
-	pp->offset = 0;
-
-	if (!pev->event) {
-		pev->event = function;
-		function = NULL;
-	}
-	if (!pev->group) {
-		char *ptr1, *ptr2, *exec_copy;
-
-		pev->group = zalloc(sizeof(char *) * 64);
-		exec_copy = strdup(exec);
-		if (!exec_copy) {
-			ret = -ENOMEM;
-			pr_warning("Failed to copy exec string.\n");
-			goto out;
-		}
-
-		ptr1 = strdup(basename(exec_copy));
-		if (ptr1) {
-			ptr2 = strpbrk(ptr1, "-._");
-			if (ptr2)
-				*ptr2 = '\0';
-			e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
-					ptr1);
-			free(ptr1);
-		}
-		free(exec_copy);
-	}
-	free(pp->function);
-	pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
-	if (!pp->function) {
-		ret = -ENOMEM;
-		pr_warning("Failed to allocate memory by zalloc.\n");
-		goto out;
-	}
-	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
-	ret = 0;
-
-out:
-	if (map) {
-		dso__delete(map->dso);
-		map__delete(map);
-	}
-	if (function)
-		free(function);
-	return ret;
-}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 538d484..2553ae0 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -79,6 +79,17 @@ struct symbol {
 void symbol__delete(struct symbol *sym);
 void symbols__delete(struct rb_root *symbols);
 
+/* symbols__for_each_entry - iterate over symbols (rb_root)
+ *
+ * @symbols: the rb_root of symbols
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @nd: the 'struct rb_node *' to use as a temporary storage
+ */
+#define symbols__for_each_entry(symbols, pos, nd)			\
+	for (nd = rb_first(symbols);					\
+	     nd && (pos = rb_entry(nd, struct symbol, rb_node));	\
+	     nd = rb_next(nd))
+
 static inline size_t symbol__size(const struct symbol *sym)
 {
 	return sym->end - sym->start + 1;

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

* [tip:perf/core] perf probe: Support distro-style debuginfo for uprobe
  2014-02-06  5:32 ` [PATCH -tip v3 11/11] perf probe: Support distro-style debuginfo for uprobe Masami Hiramatsu
@ 2014-02-22 18:01   ` tip-bot for Masami Hiramatsu
  0 siblings, 0 replies; 29+ messages in thread
From: tip-bot for Masami Hiramatsu @ 2014-02-22 18:01 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: acme, linux-kernel, mingo, dave.long, hpa, mingo, namhyung,
	masami.hiramatsu.pt, rostedt, srikar, dsahern, oleg, tglx

Commit-ID:  a15ad2f5360c821f030c53266ebf467738249c68
Gitweb:     http://git.kernel.org/tip/a15ad2f5360c821f030c53266ebf467738249c68
Author:     Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
AuthorDate: Thu, 6 Feb 2014 05:32:27 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Tue, 18 Feb 2014 09:38:44 -0300

perf probe: Support distro-style debuginfo for uprobe

Support distro-style debuginfo supported by dso for setting uprobes.
Note that this tries to find a debuginfo file based on the real path of
the target binary. If the debuginfo is not correctly installed on the
system, this can not find it.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: "David A. Long" <dave.long@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20140206053227.29635.54434.stgit@kbuild-fedora.yrl.intra.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-event.c  |  9 +++------
 tools/perf/util/probe-finder.c | 41 +++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/probe-finder.h |  1 +
 3 files changed, 43 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 42bec67..0d1542f 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -256,17 +256,14 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
 }
 
 #ifdef HAVE_DWARF_SUPPORT
+
 /* Open new debuginfo of given module */
 static struct debuginfo *open_debuginfo(const char *module)
 {
-	const char *path;
+	const char *path = module;
 
-	/* A file path -- this is an offline module */
-	if (module && strchr(module, '/'))
-		path = module;
-	else {
+	if (!module || !strchr(module, '/')) {
 		path = kernel_get_module_path(module);
-
 		if (!path) {
 			pr_err("Failed to find path of %s module.\n",
 			       module ?: "kernel");
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4f6e277..df02386 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -34,6 +34,7 @@
 
 #include <linux/bitops.h>
 #include "event.h"
+#include "dso.h"
 #include "debug.h"
 #include "intlist.h"
 #include "util.h"
@@ -89,7 +90,7 @@ error:
 	return -ENOENT;
 }
 
-struct debuginfo *debuginfo__new(const char *path)
+static struct debuginfo *__debuginfo__new(const char *path)
 {
 	struct debuginfo *dbg = zalloc(sizeof(*dbg));
 	if (!dbg)
@@ -97,10 +98,46 @@ struct debuginfo *debuginfo__new(const char *path)
 
 	if (debuginfo__init_offline_dwarf(dbg, path) < 0)
 		zfree(&dbg);
-
+	if (dbg)
+		pr_debug("Open Debuginfo file: %s\n", path);
 	return dbg;
 }
 
+enum dso_binary_type distro_dwarf_types[] = {
+	DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
+	DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
+	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
+	DSO_BINARY_TYPE__NOT_FOUND,
+};
+
+struct debuginfo *debuginfo__new(const char *path)
+{
+	enum dso_binary_type *type;
+	char buf[PATH_MAX], nil = '\0';
+	struct dso *dso;
+	struct debuginfo *dinfo = NULL;
+
+	/* Try to open distro debuginfo files */
+	dso = dso__new(path);
+	if (!dso)
+		goto out;
+
+	for (type = distro_dwarf_types;
+	     !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;
+	     type++) {
+		if (dso__read_binary_type_filename(dso, *type, &nil,
+						   buf, PATH_MAX) < 0)
+			continue;
+		dinfo = __debuginfo__new(buf);
+	}
+	dso__delete(dso);
+
+out:
+	/* if failed to open all distro debuginfo, open given binary */
+	return dinfo ? : __debuginfo__new(path);
+}
+
 void debuginfo__delete(struct debuginfo *dbg)
 {
 	if (dbg) {
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 3fc5973..92590b2 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -30,6 +30,7 @@ struct debuginfo {
 	Dwarf_Addr	bias;
 };
 
+/* This also tries to open distro debuginfo */
 extern struct debuginfo *debuginfo__new(const char *path);
 extern void debuginfo__delete(struct debuginfo *dbg);
 

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

end of thread, other threads:[~2014-02-22 18:10 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-06  5:32 [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
2014-02-06  5:32 ` [PATCH -tip v3 01/11] [BUGFIX] perf-probe: Fix to do exit call for symbol maps Masami Hiramatsu
2014-02-17  7:56   ` Namhyung Kim
2014-02-17 11:44     ` Masami Hiramatsu
2014-02-22 17:59   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
2014-02-06  5:32 ` [PATCH -tip v3 02/11] [CLEANUP] perf-probe: Remove incorrect symbol check for --list Masami Hiramatsu
2014-02-22 18:00   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
2014-02-06  5:32 ` [PATCH -tip v3 03/11] [CLEANUP] perf-probe: Replace line_list with intlist Masami Hiramatsu
2014-02-17  7:58   ` Namhyung Kim
2014-02-22 18:00   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
2014-02-06  5:32 ` [PATCH -tip v3 04/11] [CLEANUP] perf-probe: Unify show_available_functions for uprobes/kprobes Masami Hiramatsu
2014-02-22 18:00   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
2014-02-06  5:32 ` [PATCH -tip v3 05/11] perf-probe: Show in what binaries/modules probes are set Masami Hiramatsu
2014-02-22 18:00   ` [tip:perf/core] perf probe: Show in what binaries/ modules " tip-bot for Masami Hiramatsu
2014-02-06  5:32 ` [PATCH -tip v3 06/11] perf-probe: Use ref_reloc_sym based address instead of the symbol name Masami Hiramatsu
2014-02-22 18:00   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
2014-02-06  5:32 ` [PATCH -tip v3 07/11] perf-probe: Find given address from offline dwarf Masami Hiramatsu
2014-02-22 18:00   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
2014-02-06  5:32 ` [PATCH -tip v3 08/11] perf-probe: Show appropriate symbol for ref_reloc_sym based kprobes Masami Hiramatsu
2014-02-22 18:01   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
2014-02-06  5:32 ` [PATCH -tip v3 09/11] perf-probe: Show source-level or symbol-level info for uprobes Masami Hiramatsu
2014-02-22 18:01   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
2014-02-06  5:32 ` [PATCH -tip v3 10/11] perf-probe: Allow to add events on the local functions Masami Hiramatsu
2014-02-22 18:01   ` [tip:perf/core] perf probe: " tip-bot for Masami Hiramatsu
2014-02-06  5:32 ` [PATCH -tip v3 11/11] perf probe: Support distro-style debuginfo for uprobe Masami Hiramatsu
2014-02-22 18:01   ` [tip:perf/core] " tip-bot for Masami Hiramatsu
2014-02-14  5:43 ` [PATCH -tip v3 00/11] perf-probe: Updates for handling local functions correctly and distro debuginfo Masami Hiramatsu
2014-02-17 18:28   ` Arnaldo Carvalho de Melo
2014-02-17 19:04     ` Arnaldo Carvalho de Melo

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