Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Masami Hiramatsu and committed by
Arnaldo Carvalho de Melo
7cd5738d ac7a75d1

+118 -8
+57 -1
tools/perf/util/probe-event.c
··· 43 43 #include <linux/ctype.h> 44 44 #include <linux/zalloc.h> 45 45 46 + #ifdef HAVE_DEBUGINFOD_SUPPORT 47 + #include <elfutils/debuginfod.h> 48 + #endif 49 + 46 50 #define PERFPROBE_GROUP "probe" 47 51 48 52 bool probe_event_dry_run; /* Dry run flag */ ··· 342 338 343 339 map = machine__kernel_map(host_machine); 344 340 dso = map->dso; 341 + if (!dso->has_build_id) 342 + dso__read_running_kernel_build_id(dso, host_machine); 345 343 346 344 vmlinux_name = symbol_conf.vmlinux_name; 347 345 dso->load_errno = 0; ··· 459 453 return ret; 460 454 } 461 455 456 + #ifdef HAVE_DEBUGINFOD_SUPPORT 457 + static struct debuginfo *open_from_debuginfod(struct dso *dso, struct nsinfo *nsi, 458 + bool silent) 459 + { 460 + debuginfod_client *c = debuginfod_begin(); 461 + char sbuild_id[SBUILD_ID_SIZE + 1]; 462 + struct debuginfo *ret = NULL; 463 + struct nscookie nsc; 464 + char *path; 465 + int fd; 466 + 467 + if (!c) 468 + return NULL; 469 + 470 + build_id__sprintf(dso->build_id, BUILD_ID_SIZE, sbuild_id); 471 + fd = debuginfod_find_debuginfo(c, (const unsigned char *)sbuild_id, 472 + 0, &path); 473 + if (fd >= 0) 474 + close(fd); 475 + debuginfod_end(c); 476 + if (fd < 0) { 477 + if (!silent) 478 + pr_debug("Failed to find debuginfo in debuginfod.\n"); 479 + return NULL; 480 + } 481 + if (!silent) 482 + pr_debug("Load debuginfo from debuginfod (%s)\n", path); 483 + 484 + nsinfo__mountns_enter(nsi, &nsc); 485 + ret = debuginfo__new((const char *)path); 486 + nsinfo__mountns_exit(&nsc); 487 + return ret; 488 + } 489 + #else 490 + static inline 491 + struct debuginfo *open_from_debuginfod(struct dso *dso __maybe_unused, 492 + struct nsinfo *nsi __maybe_unused, 493 + bool silent __maybe_unused) 494 + { 495 + return NULL; 496 + } 497 + #endif 498 + 462 499 /* Open new debuginfo of given module */ 463 500 static struct debuginfo *open_debuginfo(const char *module, struct nsinfo *nsi, 464 501 bool silent) ··· 521 472 strcpy(reason, "(unknown)"); 522 473 } else 523 474 dso__strerror_load(dso, reason, STRERR_BUFSIZE); 475 + if (dso) 476 + ret = open_from_debuginfod(dso, nsi, silent); 477 + if (ret) 478 + return ret; 524 479 if (!silent) { 525 480 if (module) 526 481 pr_err("Module %s is not loaded, please specify its full path name.\n", module); ··· 1012 959 int ret; 1013 960 char *tmp; 1014 961 char sbuf[STRERR_BUFSIZE]; 962 + char sbuild_id[SBUILD_ID_SIZE] = ""; 1015 963 1016 964 /* Search a line range */ 1017 965 dinfo = open_debuginfo(module, NULL, false); ··· 1025 971 if (!ret) 1026 972 ret = debuginfo__find_line_range(dinfo, lr); 1027 973 } 974 + if (dinfo->build_id) 975 + build_id__sprintf(dinfo->build_id, BUILD_ID_SIZE, sbuild_id); 1028 976 debuginfo__delete(dinfo); 1029 977 if (ret == 0 || ret == -ENOENT) { 1030 978 pr_warning("Specified source line is not found.\n"); ··· 1038 982 1039 983 /* Convert source file path */ 1040 984 tmp = lr->path; 1041 - ret = get_real_path(tmp, lr->comp_dir, &lr->path); 985 + ret = find_source_path(tmp, sbuild_id, lr->comp_dir, &lr->path); 1042 986 1043 987 /* Free old path when new path is assigned */ 1044 988 if (tmp != lr->path)
+56 -5
tools/perf/util/probe-finder.c
··· 31 31 #include "probe-file.h" 32 32 #include "string2.h" 33 33 34 + #ifdef HAVE_DEBUGINFOD_SUPPORT 35 + #include <elfutils/debuginfod.h> 36 + #endif 37 + 34 38 /* Kprobe tracer basic type is up to u64 */ 35 39 #define MAX_BASIC_TYPE_BITS 64 36 40 ··· 55 51 static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, 56 52 const char *path) 57 53 { 54 + GElf_Addr dummy; 58 55 int fd; 59 56 60 57 fd = open(path, O_RDONLY); ··· 74 69 dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias); 75 70 if (!dbg->dbg) 76 71 goto error; 72 + 73 + dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy); 77 74 78 75 dwfl_report_end(dbg->dwfl, NULL, NULL); 79 76 ··· 949 942 /* Find probe points from lazy pattern */ 950 943 static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 951 944 { 945 + char sbuild_id[SBUILD_ID_SIZE] = ""; 952 946 int ret = 0; 953 947 char *fpath; 954 948 ··· 957 949 const char *comp_dir; 958 950 959 951 comp_dir = cu_get_comp_dir(&pf->cu_die); 960 - ret = get_real_path(pf->fname, comp_dir, &fpath); 952 + if (pf->dbg->build_id) 953 + build_id__sprintf(pf->dbg->build_id, 954 + BUILD_ID_SIZE, sbuild_id); 955 + ret = find_source_path(pf->fname, sbuild_id, comp_dir, &fpath); 961 956 if (ret < 0) { 962 957 pr_warning("Failed to find source file path.\n"); 963 958 return ret; ··· 1459 1448 struct probe_trace_event **tevs) 1460 1449 { 1461 1450 struct trace_event_finder tf = { 1462 - .pf = {.pev = pev, .callback = add_probe_trace_event}, 1451 + .pf = {.pev = pev, .dbg = dbg, .callback = add_probe_trace_event}, 1463 1452 .max_tevs = probe_conf.max_probes, .mod = dbg->mod}; 1464 1453 int ret, i; 1465 1454 ··· 1629 1618 struct variable_list **vls) 1630 1619 { 1631 1620 struct available_var_finder af = { 1632 - .pf = {.pev = pev, .callback = add_available_vars}, 1621 + .pf = {.pev = pev, .dbg = dbg, .callback = add_available_vars}, 1633 1622 .mod = dbg->mod, 1634 1623 .max_vls = probe_conf.max_probes}; 1635 1624 int ret; ··· 1984 1973 return (ret < 0) ? ret : lf.found; 1985 1974 } 1986 1975 1976 + #ifdef HAVE_DEBUGINFOD_SUPPORT 1977 + /* debuginfod doesn't require the comp_dir but buildid is required */ 1978 + static int get_source_from_debuginfod(const char *raw_path, 1979 + const char *sbuild_id, char **new_path) 1980 + { 1981 + debuginfod_client *c = debuginfod_begin(); 1982 + const char *p = raw_path; 1983 + int fd; 1984 + 1985 + if (!c) 1986 + return -ENOMEM; 1987 + 1988 + fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id, 1989 + 0, p, new_path); 1990 + pr_debug("Search %s from debuginfod -> %d\n", p, fd); 1991 + if (fd >= 0) 1992 + close(fd); 1993 + debuginfod_end(c); 1994 + if (fd < 0) { 1995 + pr_debug("Failed to find %s in debuginfod (%s)\n", 1996 + raw_path, sbuild_id); 1997 + return -ENOENT; 1998 + } 1999 + pr_debug("Got a source %s\n", *new_path); 2000 + 2001 + return 0; 2002 + } 2003 + #else 2004 + static inline int get_source_from_debuginfod(const char *raw_path __maybe_unused, 2005 + const char *sbuild_id __maybe_unused, 2006 + char **new_path __maybe_unused) 2007 + { 2008 + return -ENOTSUP; 2009 + } 2010 + #endif 1987 2011 /* 1988 2012 * Find a src file from a DWARF tag path. Prepend optional source path prefix 1989 2013 * and chop off leading directories that do not exist. Result is passed back as 1990 2014 * a newly allocated path on success. 1991 2015 * Return 0 if file was found and readable, -errno otherwise. 1992 2016 */ 1993 - int get_real_path(const char *raw_path, const char *comp_dir, 1994 - char **new_path) 2017 + int find_source_path(const char *raw_path, const char *sbuild_id, 2018 + const char *comp_dir, char **new_path) 1995 2019 { 1996 2020 const char *prefix = symbol_conf.source_prefix; 2021 + 2022 + if (sbuild_id && !prefix) { 2023 + if (!get_source_from_debuginfod(raw_path, sbuild_id, new_path)) 2024 + return 0; 2025 + } 1997 2026 1998 2027 if (!prefix) { 1999 2028 if (raw_path[0] != '/' && comp_dir)
+5 -2
tools/perf/util/probe-finder.h
··· 4 4 5 5 #include <stdbool.h> 6 6 #include "intlist.h" 7 + #include "build-id.h" 7 8 #include "probe-event.h" 8 9 #include <linux/ctype.h> 9 10 ··· 33 32 Dwfl_Module *mod; 34 33 Dwfl *dwfl; 35 34 Dwarf_Addr bias; 35 + const unsigned char *build_id; 36 36 }; 37 37 38 38 /* This also tries to open distro debuginfo */ ··· 61 59 struct variable_list **vls); 62 60 63 61 /* Find a src file from a DWARF tag path */ 64 - int get_real_path(const char *raw_path, const char *comp_dir, 65 - char **new_path); 62 + int find_source_path(const char *raw_path, const char *sbuild_id, 63 + const char *comp_dir, char **new_path); 66 64 67 65 struct probe_finder { 68 66 struct perf_probe_event *pev; /* Target probe event */ 67 + struct debuginfo *dbg; 69 68 70 69 /* Callback when a probe point is found */ 71 70 int (*callback)(Dwarf_Die *sc_die, struct probe_finder *pf);