Subject: [PATCH perf/core ] perf probe: Show the error reason comes from invalid DSO

Show the reason of error when dso__load* failed. This shows
when user gives wrong kernel image or wrong path.

Without this, perf probe shows an obscure message.
----
$ perf probe -k ~/kbin/linux-3.x86_64/vmlinux -L vfs_read
Failed to find path of kernel module.
Error: Failed to show lines.
----

With this, perf shows appropriate error message.
----
$ perf probe -k ~/kbin/linux-3.x86_64/vmlinux -L vfs_read
Failed to find the path for kernel: Mismatching build id
Error: Failed to show lines.
----
And
----
$ perf probe -k /non-exist/kernel/vmlinux -L vfs_read
Failed to find the path for kernel: No such file or directory
Error: Failed to show lines.
----

Signed-off-by: Masami Hiramatsu <[email protected]>
---
tools/perf/util/probe-event.c | 47 +++++++++++++++++++++--------------------
tools/perf/util/probe-event.h | 3 ---
2 files changed, 24 insertions(+), 26 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index a2d8cef..a4830a6 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -201,11 +201,12 @@ static void put_target_map(struct map *map, bool user)
}


-static struct dso *kernel_get_module_dso(const char *module)
+static int kernel_get_module_dso(const char *module, struct dso **pdso)
{
struct dso *dso;
struct map *map;
const char *vmlinux_name;
+ int ret = 0;

if (module) {
list_for_each_entry(dso, &host_machine->kernel_dsos.head,
@@ -215,30 +216,21 @@ static struct dso *kernel_get_module_dso(const char *module)
goto found;
}
pr_debug("Failed to find module %s.\n", module);
- return NULL;
+ return -ENOENT;
}

map = host_machine->vmlinux_maps[MAP__FUNCTION];
dso = map->dso;

vmlinux_name = symbol_conf.vmlinux_name;
- if (vmlinux_name) {
- if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0)
- return NULL;
- } else {
- if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
- pr_debug("Failed to load kernel map.\n");
- return NULL;
- }
- }
+ dso->load_errno = 0;
+ if (vmlinux_name)
+ ret = dso__load_vmlinux(dso, map, vmlinux_name, false, NULL);
+ else
+ ret = dso__load_vmlinux_path(dso, map, NULL);
found:
- return dso;
-}
-
-const char *kernel_get_module_path(const char *module)
-{
- struct dso *dso = kernel_get_module_dso(module);
- return (dso) ? dso->long_name : NULL;
+ *pdso = dso;
+ return ret;
}

static int convert_exec_to_group(const char *exec, char **result)
@@ -390,16 +382,25 @@ static int get_alternative_line_range(struct debuginfo *dinfo,
static struct debuginfo *open_debuginfo(const char *module, bool silent)
{
const char *path = module;
- struct debuginfo *ret;
+ char reason[STRERR_BUFSIZE];
+ struct debuginfo *ret = NULL;
+ struct dso *dso = NULL;
+ int err;

if (!module || !strchr(module, '/')) {
- path = kernel_get_module_path(module);
- if (!path) {
+ err = kernel_get_module_dso(module, &dso);
+ if (err < 0) {
+ if (!dso || dso->load_errno == 0) {
+ if (!strerror_r(-err, reason, STRERR_BUFSIZE))
+ strcpy(reason, "(unknown)");
+ } else
+ dso__strerror_load(dso, reason, STRERR_BUFSIZE);
if (!silent)
- pr_err("Failed to find path of %s module.\n",
- module ?: "kernel");
+ pr_err("Failed to find the path for %s: %s\n",
+ module ?: "kernel", reason);
return NULL;
}
+ path = dso->long_name;
}
ret = debuginfo__new(path);
if (!ret && !silent) {
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 537eb32..31db6ee 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -131,9 +131,6 @@ extern void line_range__clear(struct line_range *lr);
/* Initialize line range */
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);
-
extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs);
extern int del_perf_probe_events(struct strfilter *filter);
extern int show_perf_probe_events(struct strfilter *filter);


Subject: Re: [PATCH perf/core ] perf probe: Show the error reason comes from invalid DSO

Arnaldo, could you also apply this?

This will helps users to find the reason why perf probe failed
to open the debuginfo.

On 2015/05/12 12:40, Masami Hiramatsu wrote:
> Show the reason of error when dso__load* failed. This shows
> when user gives wrong kernel image or wrong path.
>
> Without this, perf probe shows an obscure message.
> ----
> $ perf probe -k ~/kbin/linux-3.x86_64/vmlinux -L vfs_read
> Failed to find path of kernel module.
> Error: Failed to show lines.
> ----
>
> With this, perf shows appropriate error message.
> ----
> $ perf probe -k ~/kbin/linux-3.x86_64/vmlinux -L vfs_read
> Failed to find the path for kernel: Mismatching build id
> Error: Failed to show lines.
> ----
> And
> ----
> $ perf probe -k /non-exist/kernel/vmlinux -L vfs_read
> Failed to find the path for kernel: No such file or directory
> Error: Failed to show lines.
> ----
>
> Signed-off-by: Masami Hiramatsu <[email protected]>
> ---
> tools/perf/util/probe-event.c | 47 +++++++++++++++++++++--------------------
> tools/perf/util/probe-event.h | 3 ---
> 2 files changed, 24 insertions(+), 26 deletions(-)
>
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index a2d8cef..a4830a6 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -201,11 +201,12 @@ static void put_target_map(struct map *map, bool user)
> }
>
>
> -static struct dso *kernel_get_module_dso(const char *module)
> +static int kernel_get_module_dso(const char *module, struct dso **pdso)
> {
> struct dso *dso;
> struct map *map;
> const char *vmlinux_name;
> + int ret = 0;
>
> if (module) {
> list_for_each_entry(dso, &host_machine->kernel_dsos.head,
> @@ -215,30 +216,21 @@ static struct dso *kernel_get_module_dso(const char *module)
> goto found;
> }
> pr_debug("Failed to find module %s.\n", module);
> - return NULL;
> + return -ENOENT;
> }
>
> map = host_machine->vmlinux_maps[MAP__FUNCTION];
> dso = map->dso;
>
> vmlinux_name = symbol_conf.vmlinux_name;
> - if (vmlinux_name) {
> - if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0)
> - return NULL;
> - } else {
> - if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
> - pr_debug("Failed to load kernel map.\n");
> - return NULL;
> - }
> - }
> + dso->load_errno = 0;
> + if (vmlinux_name)
> + ret = dso__load_vmlinux(dso, map, vmlinux_name, false, NULL);
> + else
> + ret = dso__load_vmlinux_path(dso, map, NULL);
> found:
> - return dso;
> -}
> -
> -const char *kernel_get_module_path(const char *module)
> -{
> - struct dso *dso = kernel_get_module_dso(module);
> - return (dso) ? dso->long_name : NULL;
> + *pdso = dso;
> + return ret;
> }
>
> static int convert_exec_to_group(const char *exec, char **result)
> @@ -390,16 +382,25 @@ static int get_alternative_line_range(struct debuginfo *dinfo,
> static struct debuginfo *open_debuginfo(const char *module, bool silent)
> {
> const char *path = module;
> - struct debuginfo *ret;
> + char reason[STRERR_BUFSIZE];
> + struct debuginfo *ret = NULL;
> + struct dso *dso = NULL;
> + int err;
>
> if (!module || !strchr(module, '/')) {
> - path = kernel_get_module_path(module);
> - if (!path) {
> + err = kernel_get_module_dso(module, &dso);
> + if (err < 0) {
> + if (!dso || dso->load_errno == 0) {
> + if (!strerror_r(-err, reason, STRERR_BUFSIZE))
> + strcpy(reason, "(unknown)");
> + } else
> + dso__strerror_load(dso, reason, STRERR_BUFSIZE);
> if (!silent)
> - pr_err("Failed to find path of %s module.\n",
> - module ?: "kernel");
> + pr_err("Failed to find the path for %s: %s\n",
> + module ?: "kernel", reason);
> return NULL;
> }
> + path = dso->long_name;
> }
> ret = debuginfo__new(path);
> if (!ret && !silent) {
> diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
> index 537eb32..31db6ee 100644
> --- a/tools/perf/util/probe-event.h
> +++ b/tools/perf/util/probe-event.h
> @@ -131,9 +131,6 @@ extern void line_range__clear(struct line_range *lr);
> /* Initialize line range */
> 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);
> -
> extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs);
> extern int del_perf_probe_events(struct strfilter *filter);
> extern int show_perf_probe_events(struct strfilter *filter);
>
>


--
Masami HIRAMATSU
Linux Technology Research Center, System Productivity Research Dept.
Center for Technology Innovation - Systems Engineering
Hitachi, Ltd., Research & Development Group
E-mail: [email protected]