perf buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Sat, 28 May 2016 15:15:37 +0000 (00:15 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 30 May 2016 16:15:03 +0000 (13:15 -0300)
Use path/to/bin/buildid/elf instead of path/to/bin/buildid
to store corresponding elf binary.
This also stores vdso in buildid/vdso, kallsyms in buildid/kallsyms.

Note that the existing caches are not updated until user adds
or updates the cache. Anyway, if there is the old style build-id
cache it falls back to use it. (IOW, it is backward compatible)

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20160528151537.16098.85815.stgit@devbox
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/build-id.c
tools/perf/util/build-id.h
tools/perf/util/dso.h
tools/perf/util/symbol.c

index 67e5966503b21099688d3f90cf903b2d58d196df..67f986c8c37877dd6a038b9bfa171fa047bc49b6 100644 (file)
@@ -144,7 +144,32 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...)
        return ret;
 }
 
-static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
+char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
+                                   size_t size)
+{
+       bool is_alloc = !!bf;
+       bool retry_old = true;
+
+       asnprintf(&bf, size, "%s/%s/%s/kallsyms",
+                 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
+retry:
+       if (!access(bf, F_OK))
+               return bf;
+       if (is_alloc)
+               free(bf);
+       if (retry_old) {
+               /* Try old style kallsyms cache */
+               asnprintf(&bf, size, "%s/%s/%s",
+                         buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
+               retry_old = false;
+               goto retry;
+       }
+
+       return NULL;
+}
+
+static 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,
@@ -154,23 +179,52 @@ static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
        return bf;
 }
 
+static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso)
+{
+       return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf");
+}
+
 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
 {
-       char build_id_hex[SBUILD_ID_SIZE];
+       bool is_kallsyms = dso__is_kallsyms((struct dso *)dso);
+       bool is_vdso = dso__is_vdso((struct dso *)dso);
+       char sbuild_id[SBUILD_ID_SIZE];
+       char *linkname;
+       bool alloc = (bf == NULL);
+       int ret;
 
        if (!dso->has_build_id)
                return NULL;
 
-       build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex);
-       return build_id__filename(build_id_hex, bf, size);
+       build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
+       linkname = build_id_cache__linkname(sbuild_id, NULL, 0);
+       if (!linkname)
+               return NULL;
+
+       /* Check if old style build_id cache */
+       if (is_regular_file(linkname))
+               ret = asnprintf(&bf, size, "%s", linkname);
+       else
+               ret = asnprintf(&bf, size, "%s/%s", linkname,
+                        build_id_cache__basename(is_kallsyms, is_vdso));
+       if (ret < 0 || (!alloc && size < (unsigned int)ret))
+               bf = NULL;
+       free(linkname);
+
+       return bf;
 }
 
 bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
 {
-       char *id_name, *ch;
+       char *id_name = NULL, *ch;
        struct stat sb;
+       char sbuild_id[SBUILD_ID_SIZE];
+
+       if (!dso->has_build_id)
+               goto err;
 
-       id_name = dso__build_id_filename(dso, bf, size);
+       build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
+       id_name = build_id_cache__linkname(sbuild_id, NULL, 0);
        if (!id_name)
                goto err;
        if (access(id_name, F_OK))
@@ -194,18 +248,14 @@ bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
        if (ch - 3 < bf)
                goto err;
 
+       free(id_name);
        return strncmp(".ko", ch - 3, 3) == 0;
 err:
-       /*
-        * If dso__build_id_filename work, get id_name again,
-        * because id_name points to bf and is broken.
-        */
-       if (id_name)
-               id_name = dso__build_id_filename(dso, bf, size);
        pr_err("Invalid build id: %s\n", id_name ? :
                                         dso->long_name ? :
                                         dso->short_name ? :
                                         "[unknown]");
+       free(id_name);
        return false;
 }
 
@@ -341,7 +391,8 @@ void disable_buildid_cache(void)
 }
 
 static char *build_id_cache__dirname_from_path(const char *name,
-                                              bool is_kallsyms, bool is_vdso)
+                                              bool is_kallsyms, bool is_vdso,
+                                              const char *sbuild_id)
 {
        char *realname = (char *)name, *filename;
        bool slash = is_kallsyms || is_vdso;
@@ -352,8 +403,9 @@ static char *build_id_cache__dirname_from_path(const char *name,
                        return NULL;
        }
 
-       if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "",
-                    is_vdso ? DSO__NAME_VDSO : realname) < 0)
+       if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "",
+                    is_vdso ? DSO__NAME_VDSO : realname,
+                    sbuild_id ? "/" : "", sbuild_id ?: "") < 0)
                filename = NULL;
 
        if (!slash)
@@ -368,7 +420,8 @@ int build_id_cache__list_build_ids(const char *pathname,
        char *dir_name;
        int ret = 0;
 
-       dir_name = build_id_cache__dirname_from_path(pathname, false, false);
+       dir_name = build_id_cache__dirname_from_path(pathname, false, false,
+                                                    NULL);
        if (!dir_name)
                return -ENOMEM;
 
@@ -385,7 +438,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
 {
        const size_t size = PATH_MAX;
        char *realname = NULL, *filename = NULL, *dir_name = NULL,
-            *linkname = zalloc(size), *targetname, *tmp;
+            *linkname = zalloc(size), *tmp;
        int err = -1;
 
        if (!is_kallsyms) {
@@ -394,14 +447,22 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
                        goto out_free;
        }
 
-       dir_name = build_id_cache__dirname_from_path(name, is_kallsyms, is_vdso);
+       dir_name = build_id_cache__dirname_from_path(name, is_kallsyms,
+                                                    is_vdso, sbuild_id);
        if (!dir_name)
                goto out_free;
 
+       /* Remove old style build-id cache */
+       if (is_regular_file(dir_name))
+               if (unlink(dir_name))
+                       goto out_free;
+
        if (mkdir_p(dir_name, 0755))
                goto out_free;
 
-       if (asprintf(&filename, "%s/%s", dir_name, sbuild_id) < 0) {
+       /* Save the allocated buildid dirname */
+       if (asprintf(&filename, "%s/%s", dir_name,
+                    build_id_cache__basename(is_kallsyms, is_vdso)) < 0) {
                filename = NULL;
                goto out_free;
        }
@@ -415,7 +476,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
                        goto out_free;
        }
 
-       if (!build_id__filename(sbuild_id, linkname, size))
+       if (!build_id_cache__linkname(sbuild_id, linkname, size))
                goto out_free;
        tmp = strrchr(linkname, '/');
        *tmp = '\0';
@@ -424,10 +485,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
                goto out_free;
 
        *tmp = '/';
-       targetname = filename + strlen(buildid_dir) - 5;
-       memcpy(targetname, "../..", 5);
+       tmp = dir_name + strlen(buildid_dir) - 5;
+       memcpy(tmp, "../..", 5);
 
-       if (symlink(targetname, linkname) == 0)
+       if (symlink(tmp, linkname) == 0)
                err = 0;
 out_free:
        if (!is_kallsyms)
@@ -452,7 +513,7 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
 bool build_id_cache__cached(const char *sbuild_id)
 {
        bool ret = false;
-       char *filename = build_id__filename(sbuild_id, NULL, 0);
+       char *filename = build_id_cache__linkname(sbuild_id, NULL, 0);
 
        if (filename && !access(filename, F_OK))
                ret = true;
@@ -471,7 +532,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
        if (filename == NULL || linkname == NULL)
                goto out_free;
 
-       if (!build_id__filename(sbuild_id, linkname, size))
+       if (!build_id_cache__linkname(sbuild_id, linkname, size))
                goto out_free;
 
        if (access(linkname, F_OK))
@@ -489,7 +550,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
        tmp = strrchr(linkname, '/') + 1;
        snprintf(tmp, size - (tmp - linkname), "%s", filename);
 
-       if (unlink(linkname))
+       if (rm_rf(linkname))
                goto out_free;
 
        err = 0;
@@ -501,7 +562,7 @@ out_free:
 
 static int dso__cache_build_id(struct dso *dso, struct machine *machine)
 {
-       bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
+       bool is_kallsyms = dso__is_kallsyms(dso);
        bool is_vdso = dso__is_vdso(dso);
        const char *name = dso->long_name;
        char nm[PATH_MAX];
index 64af3e20610d7718ecacfad3810fc4bff4ee882d..e5435f46e48e5e2ee9955a05500c6345fa1775f2 100644 (file)
@@ -14,6 +14,8 @@ struct dso;
 int build_id__sprintf(const u8 *build_id, int len, char *bf);
 int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id);
 int filename__sprintf_build_id(const char *pathname, char *sbuild_id);
+char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
+                                   size_t size);
 
 char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
 bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size);
index 0953280629cffde7373b4689c8cdf5d16e992fb5..76d79d070e21e5e41ca31172d6b779b90586f734 100644 (file)
@@ -349,6 +349,11 @@ static inline bool dso__is_kcore(struct dso *dso)
               dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE;
 }
 
+static inline bool dso__is_kallsyms(struct dso *dso)
+{
+       return dso->kernel && dso->long_name[0] != '/';
+}
+
 void dso__free_a2l(struct dso *dso);
 
 enum dso_type dso__type(struct dso *dso, struct machine *machine);
index 1df6092c8665c373be363b3d75fd6a4ded88fb0f..09c5c34ae38dd08ac21f92572ffd52def4440bd1 100644 (file)
@@ -1704,10 +1704,7 @@ proc_kallsyms:
        }
 
        /* Finally, find a cache of kallsyms */
-       scnprintf(path, sizeof(path), "%s/%s/%s",
-                 buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
-
-       if (access(path, F_OK)) {
+       if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) {
                pr_err("No kallsyms or vmlinux with build-id %s was found\n",
                       sbuild_id);
                return NULL;