|
@@ -165,8 +165,7 @@ retry:
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-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,
|
|
@@ -176,6 +175,36 @@ static char *build_id_cache__linkname(const char *sbuild_id, char *bf,
|
|
|
return bf;
|
|
|
}
|
|
|
|
|
|
+char *build_id_cache__origname(const char *sbuild_id)
|
|
|
+{
|
|
|
+ char *linkname;
|
|
|
+ char buf[PATH_MAX];
|
|
|
+ char *ret = NULL, *p;
|
|
|
+ size_t offs = 5; /* == strlen("../..") */
|
|
|
+
|
|
|
+ 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 > buf + offs)) {
|
|
|
+ *p = '\0';
|
|
|
+ if (buf[offs + 1] == '[')
|
|
|
+ offs++; /*
|
|
|
+ * This is a DSO name, like [kernel.kallsyms].
|
|
|
+ * Skip the first '/', since this is not the
|
|
|
+ * cache of a regular file.
|
|
|
+ */
|
|
|
+ ret = strdup(buf + offs); /* 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");
|
|
@@ -387,6 +416,81 @@ void disable_buildid_cache(void)
|
|
|
no_buildid_cache = true;
|
|
|
}
|
|
|
|
|
|
+static bool lsdir_bid_head_filter(const char *name __maybe_unused,
|
|
|
+ struct dirent *d __maybe_unused)
|
|
|
+{
|
|
|
+ return (strlen(d->d_name) == 2) &&
|
|
|
+ isxdigit(d->d_name[0]) && isxdigit(d->d_name[1]);
|
|
|
+}
|
|
|
+
|
|
|
+static bool lsdir_bid_tail_filter(const char *name __maybe_unused,
|
|
|
+ struct dirent *d __maybe_unused)
|
|
|
+{
|
|
|
+ int i = 0;
|
|
|
+ while (isxdigit(d->d_name[i]) && i < SBUILD_ID_SIZE - 3)
|
|
|
+ i++;
|
|
|
+ return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0');
|
|
|
+}
|
|
|
+
|
|
|
+struct strlist *build_id_cache__list_all(void)
|
|
|
+{
|
|
|
+ struct strlist *toplist, *linklist = NULL, *bidlist;
|
|
|
+ struct str_node *nd, *nd2;
|
|
|
+ char *topdir, *linkdir = NULL;
|
|
|
+ char sbuild_id[SBUILD_ID_SIZE];
|
|
|
+
|
|
|
+ /* Open the top-level directory */
|
|
|
+ if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ bidlist = strlist__new(NULL, NULL);
|
|
|
+ if (!bidlist)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ toplist = lsdir(topdir, lsdir_bid_head_filter);
|
|
|
+ if (!toplist) {
|
|
|
+ pr_debug("Error in lsdir(%s): %d\n", topdir, errno);
|
|
|
+ /* If there is no buildid cache, return an empty list */
|
|
|
+ if (errno == ENOENT)
|
|
|
+ goto out;
|
|
|
+ goto err_out;
|
|
|
+ }
|
|
|
+
|
|
|
+ strlist__for_each_entry(nd, toplist) {
|
|
|
+ if (asprintf(&linkdir, "%s/%s", topdir, nd->s) < 0)
|
|
|
+ goto err_out;
|
|
|
+ /* Open the lower-level directory */
|
|
|
+ linklist = lsdir(linkdir, lsdir_bid_tail_filter);
|
|
|
+ if (!linklist) {
|
|
|
+ pr_debug("Error in lsdir(%s): %d\n", linkdir, errno);
|
|
|
+ goto err_out;
|
|
|
+ }
|
|
|
+ strlist__for_each_entry(nd2, linklist) {
|
|
|
+ if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s",
|
|
|
+ nd->s, nd2->s) != SBUILD_ID_SIZE - 1)
|
|
|
+ goto err_out;
|
|
|
+ if (strlist__add(bidlist, sbuild_id) < 0)
|
|
|
+ goto err_out;
|
|
|
+ }
|
|
|
+ strlist__delete(linklist);
|
|
|
+ zfree(&linkdir);
|
|
|
+ }
|
|
|
+
|
|
|
+out_free:
|
|
|
+ strlist__delete(toplist);
|
|
|
+out:
|
|
|
+ free(topdir);
|
|
|
+
|
|
|
+ return bidlist;
|
|
|
+
|
|
|
+err_out:
|
|
|
+ strlist__delete(linklist);
|
|
|
+ zfree(&linkdir);
|
|
|
+ strlist__delete(bidlist);
|
|
|
+ bidlist = NULL;
|
|
|
+ goto out_free;
|
|
|
+}
|
|
|
+
|
|
|
char *build_id_cache__cachedir(const char *sbuild_id, const char *name,
|
|
|
bool is_kallsyms, bool is_vdso)
|
|
|
{
|