summaryrefslogtreecommitdiff
path: root/tools/perf/util/probe-event.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@kernel.org>2020-09-18 17:01:41 +0900
committerArnaldo Carvalho de Melo <acme@redhat.com>2020-09-18 09:20:47 -0300
commit7cd5738d0d8bb192fc86736ac7fb4a6cdb57f957 (patch)
tree8b0733fa94a1fcf3692334d30c7bf840bc21360e /tools/perf/util/probe-event.c
parentac7a75d1fbe072fc5535311ecc080f10645aeba1 (diff)
perf probe: Fall back to debuginfod query if debuginfo and source not found locally
Since 'perf probe' heavily depends on debuginfo, debuginfod gives us many benefits on the 'perf probe' command on remote machine. Especially, this will be helpful for the embedded devices which will not have enough storage, or boot with a cross-build kernel whose source code is in the host machine. This will work as similar to commit c7a14fdcb3fa7736 ("perf build-ids: Fall back to debuginfod query if debuginfo not found") Tested with: (host) $ cd PATH/TO/KBUILD/DIR/ (host) $ debuginfod -F . ... (remote) # perf probe -L vfs_read Failed to find the path for the kernel: No such file or directory Error: Failed to show lines. (remote) # export DEBUGINFOD_URLS="http://$HOST_IP:8002/" (remote) # perf probe -L vfs_read <vfs_read@...> 0 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { 2 ssize_t ret; if (!(file->f_mode & FMODE_READ)) return -EBADF; 6 if (!(file->f_mode & FMODE_CAN_READ)) return -EINVAL; 8 if (unlikely(!access_ok(buf, count))) return -EFAULT; 11 ret = rw_verify_area(READ, file, pos, count); 12 if (ret) return ret; if (count > MAX_RW_COUNT) ... (remote) # perf probe -a "vfs_read count" Added new event: probe:vfs_read (on vfs_read with count) (remote) # perf probe -l probe:vfs_read (on vfs_read@ksrc/linux/fs/read_write.c with count) Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> Reviewed-by: Frank Ch. Eigler <fche@redhat.com> Cc: Aaron Merey <amerey@redhat.com> Cc: Daniel Thompson <daniel.thompson@linaro.org> Link: http://lore.kernel.org/lkml/160041610083.912668.13659563860278615846.stgit@devnote2 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r--tools/perf/util/probe-event.c58
1 files changed, 57 insertions, 1 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 17831f186ab5..3a1b58a92673 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -43,6 +43,10 @@
#include <linux/ctype.h>
#include <linux/zalloc.h>
+#ifdef HAVE_DEBUGINFOD_SUPPORT
+#include <elfutils/debuginfod.h>
+#endif
+
#define PERFPROBE_GROUP "probe"
bool probe_event_dry_run; /* Dry run flag */
@@ -338,6 +342,8 @@ static int kernel_get_module_dso(const char *module, struct dso **pdso)
map = machine__kernel_map(host_machine);
dso = map->dso;
+ if (!dso->has_build_id)
+ dso__read_running_kernel_build_id(dso, host_machine);
vmlinux_name = symbol_conf.vmlinux_name;
dso->load_errno = 0;
@@ -453,6 +459,49 @@ static int get_alternative_line_range(struct debuginfo *dinfo,
return ret;
}
+#ifdef HAVE_DEBUGINFOD_SUPPORT
+static struct debuginfo *open_from_debuginfod(struct dso *dso, struct nsinfo *nsi,
+ bool silent)
+{
+ debuginfod_client *c = debuginfod_begin();
+ char sbuild_id[SBUILD_ID_SIZE + 1];
+ struct debuginfo *ret = NULL;
+ struct nscookie nsc;
+ char *path;
+ int fd;
+
+ if (!c)
+ return NULL;
+
+ build_id__sprintf(dso->build_id, BUILD_ID_SIZE, sbuild_id);
+ fd = debuginfod_find_debuginfo(c, (const unsigned char *)sbuild_id,
+ 0, &path);
+ if (fd >= 0)
+ close(fd);
+ debuginfod_end(c);
+ if (fd < 0) {
+ if (!silent)
+ pr_debug("Failed to find debuginfo in debuginfod.\n");
+ return NULL;
+ }
+ if (!silent)
+ pr_debug("Load debuginfo from debuginfod (%s)\n", path);
+
+ nsinfo__mountns_enter(nsi, &nsc);
+ ret = debuginfo__new((const char *)path);
+ nsinfo__mountns_exit(&nsc);
+ return ret;
+}
+#else
+static inline
+struct debuginfo *open_from_debuginfod(struct dso *dso __maybe_unused,
+ struct nsinfo *nsi __maybe_unused,
+ bool silent __maybe_unused)
+{
+ return NULL;
+}
+#endif
+
/* Open new debuginfo of given module */
static struct debuginfo *open_debuginfo(const char *module, struct nsinfo *nsi,
bool silent)
@@ -472,6 +521,10 @@ static struct debuginfo *open_debuginfo(const char *module, struct nsinfo *nsi,
strcpy(reason, "(unknown)");
} else
dso__strerror_load(dso, reason, STRERR_BUFSIZE);
+ if (dso)
+ ret = open_from_debuginfod(dso, nsi, silent);
+ if (ret)
+ return ret;
if (!silent) {
if (module)
pr_err("Module %s is not loaded, please specify its full path name.\n", module);
@@ -959,6 +1012,7 @@ static int __show_line_range(struct line_range *lr, const char *module,
int ret;
char *tmp;
char sbuf[STRERR_BUFSIZE];
+ char sbuild_id[SBUILD_ID_SIZE] = "";
/* Search a line range */
dinfo = open_debuginfo(module, NULL, false);
@@ -971,6 +1025,8 @@ static int __show_line_range(struct line_range *lr, const char *module,
if (!ret)
ret = debuginfo__find_line_range(dinfo, lr);
}
+ if (dinfo->build_id)
+ build_id__sprintf(dinfo->build_id, BUILD_ID_SIZE, sbuild_id);
debuginfo__delete(dinfo);
if (ret == 0 || ret == -ENOENT) {
pr_warning("Specified source line is not found.\n");
@@ -982,7 +1038,7 @@ static int __show_line_range(struct line_range *lr, const char *module,
/* Convert source file path */
tmp = lr->path;
- ret = get_real_path(tmp, lr->comp_dir, &lr->path);
+ ret = find_source_path(tmp, sbuild_id, lr->comp_dir, &lr->path);
/* Free old path when new path is assigned */
if (tmp != lr->path)