Commit 01412261 authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Arnaldo Carvalho de Melo

perf buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid

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: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Acked-by: default avatarNamhyung 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@devboxSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 4e4b6c06
...@@ -144,7 +144,32 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...) ...@@ -144,7 +144,32 @@ static int asnprintf(char **strp, size_t size, const char *fmt, ...)
return ret; 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; char *tmp = bf;
int ret = asnprintf(&bf, size, "%s/.build-id/%.2s/%s", buildid_dir, 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) ...@@ -154,23 +179,52 @@ static char *build_id__filename(const char *sbuild_id, char *bf, size_t size)
return bf; 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 *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) if (!dso->has_build_id)
return NULL; return NULL;
build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex); build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
return build_id__filename(build_id_hex, bf, size); 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) 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; 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) if (!id_name)
goto err; goto err;
if (access(id_name, F_OK)) 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) ...@@ -194,18 +248,14 @@ bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
if (ch - 3 < bf) if (ch - 3 < bf)
goto err; goto err;
free(id_name);
return strncmp(".ko", ch - 3, 3) == 0; return strncmp(".ko", ch - 3, 3) == 0;
err: 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 ? : pr_err("Invalid build id: %s\n", id_name ? :
dso->long_name ? : dso->long_name ? :
dso->short_name ? : dso->short_name ? :
"[unknown]"); "[unknown]");
free(id_name);
return false; return false;
} }
...@@ -341,7 +391,8 @@ void disable_buildid_cache(void) ...@@ -341,7 +391,8 @@ void disable_buildid_cache(void)
} }
static char *build_id_cache__dirname_from_path(const char *name, 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; char *realname = (char *)name, *filename;
bool slash = is_kallsyms || is_vdso; bool slash = is_kallsyms || is_vdso;
...@@ -352,8 +403,9 @@ static char *build_id_cache__dirname_from_path(const char *name, ...@@ -352,8 +403,9 @@ static char *build_id_cache__dirname_from_path(const char *name,
return NULL; return NULL;
} }
if (asprintf(&filename, "%s%s%s", buildid_dir, slash ? "/" : "", if (asprintf(&filename, "%s%s%s%s%s", buildid_dir, slash ? "/" : "",
is_vdso ? DSO__NAME_VDSO : realname) < 0) is_vdso ? DSO__NAME_VDSO : realname,
sbuild_id ? "/" : "", sbuild_id ?: "") < 0)
filename = NULL; filename = NULL;
if (!slash) if (!slash)
...@@ -368,7 +420,8 @@ int build_id_cache__list_build_ids(const char *pathname, ...@@ -368,7 +420,8 @@ int build_id_cache__list_build_ids(const char *pathname,
char *dir_name; char *dir_name;
int ret = 0; 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) if (!dir_name)
return -ENOMEM; return -ENOMEM;
...@@ -385,7 +438,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, ...@@ -385,7 +438,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
{ {
const size_t size = PATH_MAX; const size_t size = PATH_MAX;
char *realname = NULL, *filename = NULL, *dir_name = NULL, char *realname = NULL, *filename = NULL, *dir_name = NULL,
*linkname = zalloc(size), *targetname, *tmp; *linkname = zalloc(size), *tmp;
int err = -1; int err = -1;
if (!is_kallsyms) { if (!is_kallsyms) {
...@@ -394,14 +447,22 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, ...@@ -394,14 +447,22 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
goto out_free; 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) if (!dir_name)
goto out_free; 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)) if (mkdir_p(dir_name, 0755))
goto out_free; 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; filename = NULL;
goto out_free; goto out_free;
} }
...@@ -415,7 +476,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, ...@@ -415,7 +476,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
goto out_free; goto out_free;
} }
if (!build_id__filename(sbuild_id, linkname, size)) if (!build_id_cache__linkname(sbuild_id, linkname, size))
goto out_free; goto out_free;
tmp = strrchr(linkname, '/'); tmp = strrchr(linkname, '/');
*tmp = '\0'; *tmp = '\0';
...@@ -424,10 +485,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, ...@@ -424,10 +485,10 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name,
goto out_free; goto out_free;
*tmp = '/'; *tmp = '/';
targetname = filename + strlen(buildid_dir) - 5; tmp = dir_name + strlen(buildid_dir) - 5;
memcpy(targetname, "../..", 5); memcpy(tmp, "../..", 5);
if (symlink(targetname, linkname) == 0) if (symlink(tmp, linkname) == 0)
err = 0; err = 0;
out_free: out_free:
if (!is_kallsyms) if (!is_kallsyms)
...@@ -452,7 +513,7 @@ static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, ...@@ -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 build_id_cache__cached(const char *sbuild_id)
{ {
bool ret = false; 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)) if (filename && !access(filename, F_OK))
ret = true; ret = true;
...@@ -471,7 +532,7 @@ int build_id_cache__remove_s(const char *sbuild_id) ...@@ -471,7 +532,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
if (filename == NULL || linkname == NULL) if (filename == NULL || linkname == NULL)
goto out_free; goto out_free;
if (!build_id__filename(sbuild_id, linkname, size)) if (!build_id_cache__linkname(sbuild_id, linkname, size))
goto out_free; goto out_free;
if (access(linkname, F_OK)) if (access(linkname, F_OK))
...@@ -489,7 +550,7 @@ int build_id_cache__remove_s(const char *sbuild_id) ...@@ -489,7 +550,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
tmp = strrchr(linkname, '/') + 1; tmp = strrchr(linkname, '/') + 1;
snprintf(tmp, size - (tmp - linkname), "%s", filename); snprintf(tmp, size - (tmp - linkname), "%s", filename);
if (unlink(linkname)) if (rm_rf(linkname))
goto out_free; goto out_free;
err = 0; err = 0;
...@@ -501,7 +562,7 @@ int build_id_cache__remove_s(const char *sbuild_id) ...@@ -501,7 +562,7 @@ int build_id_cache__remove_s(const char *sbuild_id)
static int dso__cache_build_id(struct dso *dso, struct machine *machine) 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); bool is_vdso = dso__is_vdso(dso);
const char *name = dso->long_name; const char *name = dso->long_name;
char nm[PATH_MAX]; char nm[PATH_MAX];
......
...@@ -14,6 +14,8 @@ struct dso; ...@@ -14,6 +14,8 @@ struct dso;
int build_id__sprintf(const u8 *build_id, int len, char *bf); 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 sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id);
int filename__sprintf_build_id(const char *pathname, 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); 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); bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size);
......
...@@ -349,6 +349,11 @@ static inline bool dso__is_kcore(struct dso *dso) ...@@ -349,6 +349,11 @@ static inline bool dso__is_kcore(struct dso *dso)
dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE; 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); void dso__free_a2l(struct dso *dso);
enum dso_type dso__type(struct dso *dso, struct machine *machine); enum dso_type dso__type(struct dso *dso, struct machine *machine);
......
...@@ -1704,10 +1704,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) ...@@ -1704,10 +1704,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
} }
/* Finally, find a cache of kallsyms */ /* Finally, find a cache of kallsyms */
scnprintf(path, sizeof(path), "%s/%s/%s", if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) {
buildid_dir, DSO__NAME_KALLSYMS, sbuild_id);
if (access(path, F_OK)) {
pr_err("No kallsyms or vmlinux with build-id %s was found\n", pr_err("No kallsyms or vmlinux with build-id %s was found\n",
sbuild_id); sbuild_id);
return NULL; return NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment