18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * builtin-buildid-cache.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Builtin buildid-cache command: Manages build-id cache
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2010, Red Hat Inc.
88c2ecf20Sopenharmony_ci * Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci#include <sys/types.h>
118c2ecf20Sopenharmony_ci#include <sys/time.h>
128c2ecf20Sopenharmony_ci#include <time.h>
138c2ecf20Sopenharmony_ci#include <dirent.h>
148c2ecf20Sopenharmony_ci#include <errno.h>
158c2ecf20Sopenharmony_ci#include <unistd.h>
168c2ecf20Sopenharmony_ci#include "builtin.h"
178c2ecf20Sopenharmony_ci#include "namespaces.h"
188c2ecf20Sopenharmony_ci#include "util/debug.h"
198c2ecf20Sopenharmony_ci#include "util/header.h"
208c2ecf20Sopenharmony_ci#include <subcmd/pager.h>
218c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h>
228c2ecf20Sopenharmony_ci#include "util/strlist.h"
238c2ecf20Sopenharmony_ci#include "util/build-id.h"
248c2ecf20Sopenharmony_ci#include "util/session.h"
258c2ecf20Sopenharmony_ci#include "util/dso.h"
268c2ecf20Sopenharmony_ci#include "util/symbol.h"
278c2ecf20Sopenharmony_ci#include "util/time-utils.h"
288c2ecf20Sopenharmony_ci#include "util/util.h"
298c2ecf20Sopenharmony_ci#include "util/probe-file.h"
308c2ecf20Sopenharmony_ci#include <linux/string.h>
318c2ecf20Sopenharmony_ci#include <linux/err.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	char root_dir[PATH_MAX];
368c2ecf20Sopenharmony_ci	char *p;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	strlcpy(root_dir, proc_dir, sizeof(root_dir));
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	p = strrchr(root_dir, '/');
418c2ecf20Sopenharmony_ci	if (!p)
428c2ecf20Sopenharmony_ci		return -1;
438c2ecf20Sopenharmony_ci	*p = '\0';
448c2ecf20Sopenharmony_ci	return sysfs__sprintf_build_id(root_dir, sbuildid);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic int build_id_cache__kcore_dir(char *dir, size_t sz)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	return fetch_current_timestamp(dir, sz);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic bool same_kallsyms_reloc(const char *from_dir, char *to_dir)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	char from[PATH_MAX];
558c2ecf20Sopenharmony_ci	char to[PATH_MAX];
568c2ecf20Sopenharmony_ci	const char *name;
578c2ecf20Sopenharmony_ci	u64 addr1 = 0, addr2 = 0;
588c2ecf20Sopenharmony_ci	int i, err = -1;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	scnprintf(from, sizeof(from), "%s/kallsyms", from_dir);
618c2ecf20Sopenharmony_ci	scnprintf(to, sizeof(to), "%s/kallsyms", to_dir);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
648c2ecf20Sopenharmony_ci		err = kallsyms__get_function_start(from, name, &addr1);
658c2ecf20Sopenharmony_ci		if (!err)
668c2ecf20Sopenharmony_ci			break;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (err)
708c2ecf20Sopenharmony_ci		return false;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (kallsyms__get_function_start(to, name, &addr2))
738c2ecf20Sopenharmony_ci		return false;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	return addr1 == addr2;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic int build_id_cache__kcore_existing(const char *from_dir, char *to_dir,
798c2ecf20Sopenharmony_ci					  size_t to_dir_sz)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	char from[PATH_MAX];
828c2ecf20Sopenharmony_ci	char to[PATH_MAX];
838c2ecf20Sopenharmony_ci	char to_subdir[PATH_MAX];
848c2ecf20Sopenharmony_ci	struct dirent *dent;
858c2ecf20Sopenharmony_ci	int ret = -1;
868c2ecf20Sopenharmony_ci	DIR *d;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	d = opendir(to_dir);
898c2ecf20Sopenharmony_ci	if (!d)
908c2ecf20Sopenharmony_ci		return -1;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	scnprintf(from, sizeof(from), "%s/modules", from_dir);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	while (1) {
958c2ecf20Sopenharmony_ci		dent = readdir(d);
968c2ecf20Sopenharmony_ci		if (!dent)
978c2ecf20Sopenharmony_ci			break;
988c2ecf20Sopenharmony_ci		if (dent->d_type != DT_DIR)
998c2ecf20Sopenharmony_ci			continue;
1008c2ecf20Sopenharmony_ci		scnprintf(to, sizeof(to), "%s/%s/modules", to_dir,
1018c2ecf20Sopenharmony_ci			  dent->d_name);
1028c2ecf20Sopenharmony_ci		scnprintf(to_subdir, sizeof(to_subdir), "%s/%s",
1038c2ecf20Sopenharmony_ci			  to_dir, dent->d_name);
1048c2ecf20Sopenharmony_ci		if (!compare_proc_modules(from, to) &&
1058c2ecf20Sopenharmony_ci		    same_kallsyms_reloc(from_dir, to_subdir)) {
1068c2ecf20Sopenharmony_ci			strlcpy(to_dir, to_subdir, to_dir_sz);
1078c2ecf20Sopenharmony_ci			ret = 0;
1088c2ecf20Sopenharmony_ci			break;
1098c2ecf20Sopenharmony_ci		}
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	closedir(d);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return ret;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic int build_id_cache__add_kcore(const char *filename, bool force)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	char dir[32], sbuildid[SBUILD_ID_SIZE];
1208c2ecf20Sopenharmony_ci	char from_dir[PATH_MAX], to_dir[PATH_MAX];
1218c2ecf20Sopenharmony_ci	char *p;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	strlcpy(from_dir, filename, sizeof(from_dir));
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	p = strrchr(from_dir, '/');
1268c2ecf20Sopenharmony_ci	if (!p || strcmp(p + 1, "kcore"))
1278c2ecf20Sopenharmony_ci		return -1;
1288c2ecf20Sopenharmony_ci	*p = '\0';
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (build_id_cache__kcore_buildid(from_dir, sbuildid) < 0)
1318c2ecf20Sopenharmony_ci		return -1;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	scnprintf(to_dir, sizeof(to_dir), "%s/%s/%s",
1348c2ecf20Sopenharmony_ci		  buildid_dir, DSO__NAME_KCORE, sbuildid);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if (!force &&
1378c2ecf20Sopenharmony_ci	    !build_id_cache__kcore_existing(from_dir, to_dir, sizeof(to_dir))) {
1388c2ecf20Sopenharmony_ci		pr_debug("same kcore found in %s\n", to_dir);
1398c2ecf20Sopenharmony_ci		return 0;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	if (build_id_cache__kcore_dir(dir, sizeof(dir)))
1438c2ecf20Sopenharmony_ci		return -1;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	scnprintf(to_dir, sizeof(to_dir), "%s/%s/%s/%s",
1468c2ecf20Sopenharmony_ci		  buildid_dir, DSO__NAME_KCORE, sbuildid, dir);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (mkdir_p(to_dir, 0755))
1498c2ecf20Sopenharmony_ci		return -1;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (kcore_copy(from_dir, to_dir)) {
1528c2ecf20Sopenharmony_ci		/* Remove YYYYmmddHHMMSShh directory */
1538c2ecf20Sopenharmony_ci		if (!rmdir(to_dir)) {
1548c2ecf20Sopenharmony_ci			p = strrchr(to_dir, '/');
1558c2ecf20Sopenharmony_ci			if (p)
1568c2ecf20Sopenharmony_ci				*p = '\0';
1578c2ecf20Sopenharmony_ci			/* Try to remove buildid directory */
1588c2ecf20Sopenharmony_ci			if (!rmdir(to_dir)) {
1598c2ecf20Sopenharmony_ci				p = strrchr(to_dir, '/');
1608c2ecf20Sopenharmony_ci				if (p)
1618c2ecf20Sopenharmony_ci					*p = '\0';
1628c2ecf20Sopenharmony_ci				/* Try to remove [kernel.kcore] directory */
1638c2ecf20Sopenharmony_ci				rmdir(to_dir);
1648c2ecf20Sopenharmony_ci			}
1658c2ecf20Sopenharmony_ci		}
1668c2ecf20Sopenharmony_ci		return -1;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	pr_debug("kcore added to build-id cache directory %s\n", to_dir);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return 0;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int build_id_cache__add_file(const char *filename, struct nsinfo *nsi)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	char sbuild_id[SBUILD_ID_SIZE];
1778c2ecf20Sopenharmony_ci	struct build_id bid;
1788c2ecf20Sopenharmony_ci	int err;
1798c2ecf20Sopenharmony_ci	struct nscookie nsc;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	nsinfo__mountns_enter(nsi, &nsc);
1828c2ecf20Sopenharmony_ci	err = filename__read_build_id(filename, &bid);
1838c2ecf20Sopenharmony_ci	nsinfo__mountns_exit(&nsc);
1848c2ecf20Sopenharmony_ci	if (err < 0) {
1858c2ecf20Sopenharmony_ci		pr_debug("Couldn't read a build-id in %s\n", filename);
1868c2ecf20Sopenharmony_ci		return -1;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	build_id__sprintf(&bid, sbuild_id);
1908c2ecf20Sopenharmony_ci	err = build_id_cache__add_s(sbuild_id, filename, nsi,
1918c2ecf20Sopenharmony_ci				    false, false);
1928c2ecf20Sopenharmony_ci	pr_debug("Adding %s %s: %s\n", sbuild_id, filename,
1938c2ecf20Sopenharmony_ci		 err ? "FAIL" : "Ok");
1948c2ecf20Sopenharmony_ci	return err;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int build_id_cache__remove_file(const char *filename, struct nsinfo *nsi)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	char sbuild_id[SBUILD_ID_SIZE];
2008c2ecf20Sopenharmony_ci	struct build_id bid;
2018c2ecf20Sopenharmony_ci	struct nscookie nsc;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	int err;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	nsinfo__mountns_enter(nsi, &nsc);
2068c2ecf20Sopenharmony_ci	err = filename__read_build_id(filename, &bid);
2078c2ecf20Sopenharmony_ci	nsinfo__mountns_exit(&nsc);
2088c2ecf20Sopenharmony_ci	if (err < 0) {
2098c2ecf20Sopenharmony_ci		pr_debug("Couldn't read a build-id in %s\n", filename);
2108c2ecf20Sopenharmony_ci		return -1;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	build_id__sprintf(&bid, sbuild_id);
2148c2ecf20Sopenharmony_ci	err = build_id_cache__remove_s(sbuild_id);
2158c2ecf20Sopenharmony_ci	pr_debug("Removing %s %s: %s\n", sbuild_id, filename,
2168c2ecf20Sopenharmony_ci		 err ? "FAIL" : "Ok");
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return err;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic int build_id_cache__purge_path(const char *pathname, struct nsinfo *nsi)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct strlist *list;
2248c2ecf20Sopenharmony_ci	struct str_node *pos;
2258c2ecf20Sopenharmony_ci	int err;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	err = build_id_cache__list_build_ids(pathname, nsi, &list);
2288c2ecf20Sopenharmony_ci	if (err)
2298c2ecf20Sopenharmony_ci		goto out;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	strlist__for_each_entry(pos, list) {
2328c2ecf20Sopenharmony_ci		err = build_id_cache__remove_s(pos->s);
2338c2ecf20Sopenharmony_ci		pr_debug("Removing %s %s: %s\n", pos->s, pathname,
2348c2ecf20Sopenharmony_ci			 err ? "FAIL" : "Ok");
2358c2ecf20Sopenharmony_ci		if (err)
2368c2ecf20Sopenharmony_ci			break;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci	strlist__delete(list);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ciout:
2418c2ecf20Sopenharmony_ci	pr_debug("Purging %s: %s\n", pathname, err ? "FAIL" : "Ok");
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	return err;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic int build_id_cache__purge_all(void)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	struct strlist *list;
2498c2ecf20Sopenharmony_ci	struct str_node *pos;
2508c2ecf20Sopenharmony_ci	int err = 0;
2518c2ecf20Sopenharmony_ci	char *buf;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	list = build_id_cache__list_all(false);
2548c2ecf20Sopenharmony_ci	if (!list) {
2558c2ecf20Sopenharmony_ci		pr_debug("Failed to get buildids: -%d\n", errno);
2568c2ecf20Sopenharmony_ci		return -EINVAL;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	strlist__for_each_entry(pos, list) {
2608c2ecf20Sopenharmony_ci		buf = build_id_cache__origname(pos->s);
2618c2ecf20Sopenharmony_ci		err = build_id_cache__remove_s(pos->s);
2628c2ecf20Sopenharmony_ci		pr_debug("Removing %s (%s): %s\n", buf, pos->s,
2638c2ecf20Sopenharmony_ci			 err ? "FAIL" : "Ok");
2648c2ecf20Sopenharmony_ci		free(buf);
2658c2ecf20Sopenharmony_ci		if (err)
2668c2ecf20Sopenharmony_ci			break;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci	strlist__delete(list);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	pr_debug("Purged all: %s\n", err ? "FAIL" : "Ok");
2718c2ecf20Sopenharmony_ci	return err;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	char filename[PATH_MAX];
2778c2ecf20Sopenharmony_ci	struct build_id bid;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (dso__build_id_filename(dso, filename, sizeof(filename), false) &&
2808c2ecf20Sopenharmony_ci	    filename__read_build_id(filename, &bid) == -1) {
2818c2ecf20Sopenharmony_ci		if (errno == ENOENT)
2828c2ecf20Sopenharmony_ci			return false;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci		pr_warning("Problems with %s file, consider removing it from the cache\n",
2858c2ecf20Sopenharmony_ci			   filename);
2868c2ecf20Sopenharmony_ci	} else if (memcmp(dso->bid.data, bid.data, bid.size)) {
2878c2ecf20Sopenharmony_ci		pr_warning("Problems with %s file, consider removing it from the cache\n",
2888c2ecf20Sopenharmony_ci			   filename);
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	return true;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic int build_id_cache__fprintf_missing(struct perf_session *session, FILE *fp)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0);
2978c2ecf20Sopenharmony_ci	return 0;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic int build_id_cache__update_file(const char *filename, struct nsinfo *nsi)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	char sbuild_id[SBUILD_ID_SIZE];
3038c2ecf20Sopenharmony_ci	struct build_id bid;
3048c2ecf20Sopenharmony_ci	struct nscookie nsc;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	int err;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	nsinfo__mountns_enter(nsi, &nsc);
3098c2ecf20Sopenharmony_ci	err = filename__read_build_id(filename, &bid);
3108c2ecf20Sopenharmony_ci	nsinfo__mountns_exit(&nsc);
3118c2ecf20Sopenharmony_ci	if (err < 0) {
3128c2ecf20Sopenharmony_ci		pr_debug("Couldn't read a build-id in %s\n", filename);
3138c2ecf20Sopenharmony_ci		return -1;
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci	err = 0;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	build_id__sprintf(&bid, sbuild_id);
3188c2ecf20Sopenharmony_ci	if (build_id_cache__cached(sbuild_id))
3198c2ecf20Sopenharmony_ci		err = build_id_cache__remove_s(sbuild_id);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (!err)
3228c2ecf20Sopenharmony_ci		err = build_id_cache__add_s(sbuild_id, filename, nsi, false,
3238c2ecf20Sopenharmony_ci					    false);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	pr_debug("Updating %s %s: %s\n", sbuild_id, filename,
3268c2ecf20Sopenharmony_ci		 err ? "FAIL" : "Ok");
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	return err;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic int build_id_cache__show_all(void)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct strlist *bidlist;
3348c2ecf20Sopenharmony_ci	struct str_node *nd;
3358c2ecf20Sopenharmony_ci	char *buf;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	bidlist = build_id_cache__list_all(true);
3388c2ecf20Sopenharmony_ci	if (!bidlist) {
3398c2ecf20Sopenharmony_ci		pr_debug("Failed to get buildids: -%d\n", errno);
3408c2ecf20Sopenharmony_ci		return -1;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci	strlist__for_each_entry(nd, bidlist) {
3438c2ecf20Sopenharmony_ci		buf = build_id_cache__origname(nd->s);
3448c2ecf20Sopenharmony_ci		fprintf(stdout, "%s %s\n", nd->s, buf);
3458c2ecf20Sopenharmony_ci		free(buf);
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci	strlist__delete(bidlist);
3488c2ecf20Sopenharmony_ci	return 0;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ciint cmd_buildid_cache(int argc, const char **argv)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	struct strlist *list;
3548c2ecf20Sopenharmony_ci	struct str_node *pos;
3558c2ecf20Sopenharmony_ci	int ret = 0;
3568c2ecf20Sopenharmony_ci	int ns_id = -1;
3578c2ecf20Sopenharmony_ci	bool force = false;
3588c2ecf20Sopenharmony_ci	bool list_files = false;
3598c2ecf20Sopenharmony_ci	bool opts_flag = false;
3608c2ecf20Sopenharmony_ci	bool purge_all = false;
3618c2ecf20Sopenharmony_ci	char const *add_name_list_str = NULL,
3628c2ecf20Sopenharmony_ci		   *remove_name_list_str = NULL,
3638c2ecf20Sopenharmony_ci		   *purge_name_list_str = NULL,
3648c2ecf20Sopenharmony_ci		   *missing_filename = NULL,
3658c2ecf20Sopenharmony_ci		   *update_name_list_str = NULL,
3668c2ecf20Sopenharmony_ci		   *kcore_filename = NULL;
3678c2ecf20Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	struct perf_data data = {
3708c2ecf20Sopenharmony_ci		.mode  = PERF_DATA_MODE_READ,
3718c2ecf20Sopenharmony_ci	};
3728c2ecf20Sopenharmony_ci	struct perf_session *session = NULL;
3738c2ecf20Sopenharmony_ci	struct nsinfo *nsi = NULL;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	const struct option buildid_cache_options[] = {
3768c2ecf20Sopenharmony_ci	OPT_STRING('a', "add", &add_name_list_str,
3778c2ecf20Sopenharmony_ci		   "file list", "file(s) to add"),
3788c2ecf20Sopenharmony_ci	OPT_STRING('k', "kcore", &kcore_filename,
3798c2ecf20Sopenharmony_ci		   "file", "kcore file to add"),
3808c2ecf20Sopenharmony_ci	OPT_STRING('r', "remove", &remove_name_list_str, "file list",
3818c2ecf20Sopenharmony_ci		    "file(s) to remove"),
3828c2ecf20Sopenharmony_ci	OPT_STRING('p', "purge", &purge_name_list_str, "file list",
3838c2ecf20Sopenharmony_ci		    "file(s) to remove (remove old caches too)"),
3848c2ecf20Sopenharmony_ci	OPT_BOOLEAN('P', "purge-all", &purge_all, "purge all cached files"),
3858c2ecf20Sopenharmony_ci	OPT_BOOLEAN('l', "list", &list_files, "list all cached files"),
3868c2ecf20Sopenharmony_ci	OPT_STRING('M', "missing", &missing_filename, "file",
3878c2ecf20Sopenharmony_ci		   "to find missing build ids in the cache"),
3888c2ecf20Sopenharmony_ci	OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
3898c2ecf20Sopenharmony_ci	OPT_STRING('u', "update", &update_name_list_str, "file list",
3908c2ecf20Sopenharmony_ci		    "file(s) to update"),
3918c2ecf20Sopenharmony_ci	OPT_INCR('v', "verbose", &verbose, "be more verbose"),
3928c2ecf20Sopenharmony_ci	OPT_INTEGER(0, "target-ns", &ns_id, "target pid for namespace context"),
3938c2ecf20Sopenharmony_ci	OPT_END()
3948c2ecf20Sopenharmony_ci	};
3958c2ecf20Sopenharmony_ci	const char * const buildid_cache_usage[] = {
3968c2ecf20Sopenharmony_ci		"perf buildid-cache [<options>]",
3978c2ecf20Sopenharmony_ci		NULL
3988c2ecf20Sopenharmony_ci	};
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	argc = parse_options(argc, argv, buildid_cache_options,
4018c2ecf20Sopenharmony_ci			     buildid_cache_usage, 0);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	opts_flag = add_name_list_str || kcore_filename ||
4048c2ecf20Sopenharmony_ci		remove_name_list_str || purge_name_list_str ||
4058c2ecf20Sopenharmony_ci		missing_filename || update_name_list_str ||
4068c2ecf20Sopenharmony_ci		purge_all;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	if (argc || !(list_files || opts_flag))
4098c2ecf20Sopenharmony_ci		usage_with_options(buildid_cache_usage, buildid_cache_options);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* -l is exclusive. It can not be used with other options. */
4128c2ecf20Sopenharmony_ci	if (list_files && opts_flag) {
4138c2ecf20Sopenharmony_ci		usage_with_options_msg(buildid_cache_usage,
4148c2ecf20Sopenharmony_ci			buildid_cache_options, "-l is exclusive.\n");
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	if (ns_id > 0)
4188c2ecf20Sopenharmony_ci		nsi = nsinfo__new(ns_id);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (missing_filename) {
4218c2ecf20Sopenharmony_ci		data.path  = missing_filename;
4228c2ecf20Sopenharmony_ci		data.force = force;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		session = perf_session__new(&data, false, NULL);
4258c2ecf20Sopenharmony_ci		if (IS_ERR(session))
4268c2ecf20Sopenharmony_ci			return PTR_ERR(session);
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if (symbol__init(session ? &session->header.env : NULL) < 0)
4308c2ecf20Sopenharmony_ci		goto out;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	setup_pager();
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (list_files) {
4358c2ecf20Sopenharmony_ci		ret = build_id_cache__show_all();
4368c2ecf20Sopenharmony_ci		goto out;
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	if (add_name_list_str) {
4408c2ecf20Sopenharmony_ci		list = strlist__new(add_name_list_str, NULL);
4418c2ecf20Sopenharmony_ci		if (list) {
4428c2ecf20Sopenharmony_ci			strlist__for_each_entry(pos, list)
4438c2ecf20Sopenharmony_ci				if (build_id_cache__add_file(pos->s, nsi)) {
4448c2ecf20Sopenharmony_ci					if (errno == EEXIST) {
4458c2ecf20Sopenharmony_ci						pr_debug("%s already in the cache\n",
4468c2ecf20Sopenharmony_ci							 pos->s);
4478c2ecf20Sopenharmony_ci						continue;
4488c2ecf20Sopenharmony_ci					}
4498c2ecf20Sopenharmony_ci					pr_warning("Couldn't add %s: %s\n",
4508c2ecf20Sopenharmony_ci						   pos->s, str_error_r(errno, sbuf, sizeof(sbuf)));
4518c2ecf20Sopenharmony_ci				}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci			strlist__delete(list);
4548c2ecf20Sopenharmony_ci		}
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	if (remove_name_list_str) {
4588c2ecf20Sopenharmony_ci		list = strlist__new(remove_name_list_str, NULL);
4598c2ecf20Sopenharmony_ci		if (list) {
4608c2ecf20Sopenharmony_ci			strlist__for_each_entry(pos, list)
4618c2ecf20Sopenharmony_ci				if (build_id_cache__remove_file(pos->s, nsi)) {
4628c2ecf20Sopenharmony_ci					if (errno == ENOENT) {
4638c2ecf20Sopenharmony_ci						pr_debug("%s wasn't in the cache\n",
4648c2ecf20Sopenharmony_ci							 pos->s);
4658c2ecf20Sopenharmony_ci						continue;
4668c2ecf20Sopenharmony_ci					}
4678c2ecf20Sopenharmony_ci					pr_warning("Couldn't remove %s: %s\n",
4688c2ecf20Sopenharmony_ci						   pos->s, str_error_r(errno, sbuf, sizeof(sbuf)));
4698c2ecf20Sopenharmony_ci				}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci			strlist__delete(list);
4728c2ecf20Sopenharmony_ci		}
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	if (purge_name_list_str) {
4768c2ecf20Sopenharmony_ci		list = strlist__new(purge_name_list_str, NULL);
4778c2ecf20Sopenharmony_ci		if (list) {
4788c2ecf20Sopenharmony_ci			strlist__for_each_entry(pos, list)
4798c2ecf20Sopenharmony_ci				if (build_id_cache__purge_path(pos->s, nsi)) {
4808c2ecf20Sopenharmony_ci					if (errno == ENOENT) {
4818c2ecf20Sopenharmony_ci						pr_debug("%s wasn't in the cache\n",
4828c2ecf20Sopenharmony_ci							 pos->s);
4838c2ecf20Sopenharmony_ci						continue;
4848c2ecf20Sopenharmony_ci					}
4858c2ecf20Sopenharmony_ci					pr_warning("Couldn't remove %s: %s\n",
4868c2ecf20Sopenharmony_ci						   pos->s, str_error_r(errno, sbuf, sizeof(sbuf)));
4878c2ecf20Sopenharmony_ci				}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci			strlist__delete(list);
4908c2ecf20Sopenharmony_ci		}
4918c2ecf20Sopenharmony_ci	}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	if (purge_all) {
4948c2ecf20Sopenharmony_ci		if (build_id_cache__purge_all()) {
4958c2ecf20Sopenharmony_ci			pr_warning("Couldn't remove some caches. Error: %s.\n",
4968c2ecf20Sopenharmony_ci				str_error_r(errno, sbuf, sizeof(sbuf)));
4978c2ecf20Sopenharmony_ci		}
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	if (missing_filename)
5018c2ecf20Sopenharmony_ci		ret = build_id_cache__fprintf_missing(session, stdout);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if (update_name_list_str) {
5048c2ecf20Sopenharmony_ci		list = strlist__new(update_name_list_str, NULL);
5058c2ecf20Sopenharmony_ci		if (list) {
5068c2ecf20Sopenharmony_ci			strlist__for_each_entry(pos, list)
5078c2ecf20Sopenharmony_ci				if (build_id_cache__update_file(pos->s, nsi)) {
5088c2ecf20Sopenharmony_ci					if (errno == ENOENT) {
5098c2ecf20Sopenharmony_ci						pr_debug("%s wasn't in the cache\n",
5108c2ecf20Sopenharmony_ci							 pos->s);
5118c2ecf20Sopenharmony_ci						continue;
5128c2ecf20Sopenharmony_ci					}
5138c2ecf20Sopenharmony_ci					pr_warning("Couldn't update %s: %s\n",
5148c2ecf20Sopenharmony_ci						   pos->s, str_error_r(errno, sbuf, sizeof(sbuf)));
5158c2ecf20Sopenharmony_ci				}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci			strlist__delete(list);
5188c2ecf20Sopenharmony_ci		}
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	if (kcore_filename && build_id_cache__add_kcore(kcore_filename, force))
5228c2ecf20Sopenharmony_ci		pr_warning("Couldn't add %s\n", kcore_filename);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ciout:
5258c2ecf20Sopenharmony_ci	perf_session__delete(session);
5268c2ecf20Sopenharmony_ci	nsinfo__zput(nsi);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	return ret;
5298c2ecf20Sopenharmony_ci}
530