From: Masami Hiramatsu <masami.hiramatsu...@hitachi.com>

perf probe --list shows all cached probes when --cache
is given. Each caches are shown with on which binary that
probed. e.g.
  -----
  # perf probe --cache vfs_read \$params
  # perf probe --cache -x /lib64/libc-2.17.so getaddrinfo \$params
  # perf probe --cache --list
  /[kernel.kallsyms] (1466a0a250b5d0070c6d0f03c5fed30b237970a1):
  vfs_read $params
  /usr/lib64/libc-2.17.so (c31ffe7942bfd77b2fca8f9bd5709d387a86d3bc):
  getaddrinfo $params
  -----
Note that $params requires debuginfo.

Signed-off-by: Masami Hiramatsu <masami.hiramatsu...@hitachi.com>
Signed-off-by: Masami Hiramatsu <mhira...@kernel.org>
---
 tools/perf/Documentation/perf-probe.txt |    8 ++-
 tools/perf/builtin-probe.c              |    2 -
 tools/perf/util/build-id.c              |   79 ++++++++++++++++++++++++++++++-
 tools/perf/util/build-id.h              |    3 +
 tools/perf/util/probe-event.c           |    3 +
 tools/perf/util/probe-file.c            |   67 ++++++++++++++++++++++++++
 tools/perf/util/probe-file.h            |    1 
 7 files changed, 156 insertions(+), 7 deletions(-)

diff --git a/tools/perf/Documentation/perf-probe.txt 
b/tools/perf/Documentation/perf-probe.txt
index 947db6f..5a70d45 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -67,7 +67,10 @@ OPTIONS
 
 -l::
 --list[=[GROUP:]EVENT]::
-       List up current probe events. This can also accept filtering patterns 
of event names.
+       List up current probe events. This can also accept filtering patterns of
+       event names.
+       When this is used with --cache, perf shows all cached probes instead of
+       the live probes.
 
 -L::
 --line=::
@@ -110,8 +113,9 @@ OPTIONS
        adding and removal operations.
 
 --cache::
-       Cache the probes (with --add option). Any events which successfully 
added
+       (With --add) Cache the probes. Any events which successfully added
        are also stored in the cache file.
+       (With --list) Show cached probes.
 
 --max-probes=NUM::
        Set the maximum number of probe points for an event. Default is 128.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 6d7ab431..53e380c0e 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -44,7 +44,7 @@
 
 #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
 #define DEFAULT_FUNC_FILTER "!_*"
-#define DEFAULT_LIST_FILTER "*:*"
+#define DEFAULT_LIST_FILTER "*"
 
 /* Session management structure */
 static struct {
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 588ff01..a7da315 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -144,8 +144,7 @@ static int asnprintf(char **strp, size_t size, const char 
*fmt, ...)
        return ret;
 }
 
-static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
-                                     size_t size)
+char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size)
 {
        char *tmp = bf;
        int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
@@ -161,6 +160,29 @@ static bool __is_regular_file(const char *pathname)
        return stat(pathname, &sb) == 0 && S_ISREG(sb.st_mode);
 }
 
+char *build_id_cache__origname(const char *sbuild_id)
+{
+       char *linkname;
+       char buf[PATH_MAX];
+       char *ret = NULL, *p;
+
+       linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
+       if (!linkname)
+               return NULL;
+
+       if (readlink(linkname, buf, PATH_MAX) < 0)
+               goto out;
+       /* The link should be "../..<origpath>/<sbuild_id>" */
+       p = strrchr(buf, '/');  /* Cut off the "/<sbuild_id>" */
+       if (p) {
+               *p = '\0';
+               ret = strdup(buf + 5);  /* Skip "../.." */
+       }
+out:
+       free(linkname);
+       return ret;
+}
+
 static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
 {
        return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
@@ -371,6 +393,59 @@ void disable_buildid_cache(void)
        no_buildid_cache = true;
 }
 
+int build_id_cache__list_all(struct strlist **result)
+{
+       struct strlist *toplist, *list, *bidlist;
+       struct str_node *nd, *nd2;
+       char *topdir, *linkdir;
+       char sbuild_id[SBUILD_ID_SIZE];
+       int ret = 0;
+
+       /* Open the top-level directory */
+       if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
+               return -errno;
+       toplist = lsdir(topdir, lsdir_no_dot_filter);
+       if (!toplist) {
+               pr_debug("Failed to opendir %s\n", topdir);
+               ret = -errno;
+               goto out;
+       }
+       bidlist = strlist__new(NULL, NULL);
+       strlist__for_each(nd, toplist) {
+               if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0) {
+                       ret = -errno;
+                       goto out;
+               }
+               /* Open the lower-level directory */
+               list = lsdir(linkdir, lsdir_no_dot_filter);
+               if (!list) {
+                       pr_debug("Failed to open %s: %d\n", linkdir, -errno);
+                       goto next;
+               }
+               strlist__for_each(nd2, list) {
+                       ret = snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
+                                       nd->s, nd2->s);
+                       if (ret != SBUILD_ID_SIZE - 1) {
+                               pr_debug("%s/%s is not buildid cache\n",
+                                       nd->s, nd2->s);
+                               continue;
+                       }
+                       strlist__add(bidlist, sbuild_id);
+               }
+               strlist__delete(list);
+next:
+               free(linkdir);
+       }
+
+       *result = bidlist;
+out:
+       if (toplist)
+               strlist__delete(toplist);
+       free(topdir);
+
+       return ret;
+}
+
 char *build_id_cache__dirname_from_path(const char *sbuild_id, const char 
*name,
                                        bool is_kallsyms, bool is_vdso)
 {
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 1841524..2c98a39 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -28,8 +28,11 @@ bool perf_session__read_build_ids(struct perf_session 
*session, bool with_hits);
 int perf_session__write_buildid_table(struct perf_session *session, int fd);
 int perf_session__cache_build_ids(struct perf_session *session);
 
+char *build_id_cache__origname(const char *sbuild_id);
+char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size);
 char *build_id_cache__dirname_from_path(const char *sbuild_id, const char 
*name,
                                        bool is_kallsyms, bool is_vdso);
+int build_id_cache__list_all(struct strlist **result);
 int build_id_cache__list_build_ids(const char *pathname,
                                   struct strlist **result);
 bool build_id_cache__cached(const char *sbuild_id);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 0cd709e..8bea724 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2335,6 +2335,9 @@ int show_perf_probe_events(struct strfilter *filter)
 
        setup_pager();
 
+       if (probe_conf.cache)
+               return probe_cache__show_all_caches(filter);
+
        ret = init_probe_symbol_maps(false);
        if (ret < 0)
                return ret;
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 0d1298f..72d58e7 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -365,10 +365,17 @@ static int probe_cache__open(struct probe_cache *pcache, 
const char *target)
 {
        char cpath[PATH_MAX];
        char sbuildid[SBUILD_ID_SIZE];
-       char *dir_name;
+       char *dir_name = NULL;
        bool is_kallsyms = !target;
        int ret, fd;
 
+       if (target && build_id_cache__cached(target)) {
+               /* This is a cached buildid */
+               strncpy(sbuildid, target, SBUILD_ID_SIZE);
+               dir_name = build_id_cache__linkname(sbuildid, NULL, 0);
+               goto found;
+       }
+
        if (target)
                ret = filename__sprintf_build_id(target, sbuildid);
        else {
@@ -392,8 +399,11 @@ static int probe_cache__open(struct probe_cache *pcache, 
const char *target)
 
        dir_name = build_id_cache__dirname_from_path(sbuildid, target,
                                                     is_kallsyms, false);
-       if (!dir_name)
+found:
+       if (!dir_name) {
+               pr_debug("Failed to get cache from %s\n", target);
                return -ENOMEM;
+       }
 
        snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
        fd = open(cpath, O_CREAT | O_RDWR | O_APPEND, 0644);
@@ -641,3 +651,56 @@ int probe_cache__commit(struct probe_cache *pcache)
 out:
        return ret;
 }
+
+static int probe_cache__show_entries(struct probe_cache *pcache,
+                                    struct strfilter *filter)
+{
+       struct probe_cache_entry *entry;
+       char buf[128], *ptr;
+
+       list_for_each_entry(entry, &pcache->list, list) {
+               if (entry->pev.event) {
+                       ptr = buf;
+                       snprintf(buf, 128, "%s:%s", entry->pev.group, 
entry->pev.event);
+               } else
+                       ptr = entry->spev;
+               if (strfilter__compare(filter, ptr))
+                       printf("%s\n", entry->spev);
+       }
+       return 0;
+}
+
+/* Show all cached probes */
+int probe_cache__show_all_caches(struct strfilter *filter)
+{
+       struct probe_cache *pcache;
+       struct strlist *bidlist;
+       struct str_node *nd;
+       char *buf;
+       int ret;
+
+       buf = strfilter__string(filter);
+       pr_debug("list cache with filter: %s\n", buf);
+       free(buf);
+
+       ret = build_id_cache__list_all(&bidlist);
+       if (ret < 0) {
+               pr_debug("Failed to get buildids: %d\n", ret);
+               return ret == -ENOENT ? 0 : ret;
+       }
+       strlist__for_each(nd, bidlist) {
+               pcache = probe_cache__new(nd->s);
+               if (!pcache)
+                       continue;
+               if (!list_empty(&pcache->list)) {
+                       buf = build_id_cache__origname(nd->s);
+                       printf("%s (%s):\n", buf, nd->s);
+                       free(buf);
+                       probe_cache__show_entries(pcache, filter);
+               }
+               probe_cache__delete(pcache);
+       }
+       strlist__delete(bidlist);
+
+       return 0;
+}
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h
index 1385c8b..ac70446 100644
--- a/tools/perf/util/probe-file.h
+++ b/tools/perf/util/probe-file.h
@@ -41,4 +41,5 @@ struct probe_cache_entry *probe_cache__find(struct 
probe_cache *pcache,
                                            struct perf_probe_event *pev);
 struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache,
                                        const char *group, const char *event);
+int probe_cache__show_all_caches(struct strfilter *filter);
 #endif

Reply via email to