xref: /openbmc/linux/tools/perf/util/util.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
24cf40131SArnaldo Carvalho de Melo #include "util.h"
384f5d36fSJiri Olsa #include "debug.h"
48520a98dSArnaldo Carvalho de Melo #include "event.h"
5cd0cfad7SBorislav Petkov #include <api/fs/fs.h>
67a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h>
707bc5c69SWang Nan #include <sys/utsname.h>
876b31a29SArnaldo Carvalho de Melo #include <dirent.h>
9c23c2a0fSArnaldo Carvalho de Melo #include <fcntl.h>
10fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
119607ad3aSArnaldo Carvalho de Melo #include <signal.h>
12dc4552bfSArnaldo Carvalho de Melo #include <stdio.h>
13dc4552bfSArnaldo Carvalho de Melo #include <stdlib.h>
14cef82c9fSJiri Olsa #include <string.h>
15cef82c9fSJiri Olsa #include <errno.h>
161a47245dSAdrian Hunter #include <limits.h>
17c22e150eSIgor Lubashev #include <linux/capability.h>
18838d1452SJiri Olsa #include <linux/kernel.h>
19c339b1a9SWang Nan #include <linux/log2.h>
20bd48c63eSArnaldo Carvalho de Melo #include <linux/time64.h>
2110d34700SAdrian Hunter #include <linux/overflow.h>
229398c484SJiri Olsa #include <unistd.h>
23c22e150eSIgor Lubashev #include "cap.h"
2414cbfbebSNamhyung Kim #include "strlist.h"
25cdb6b023SJiri Olsa #include "string2.h"
2623aadb1fSJiri Olsa 
271aed2671SJoerg Roedel /*
281aed2671SJoerg Roedel  * XXX We need to find a better place for these things...
291aed2671SJoerg Roedel  */
300a7c74eaSArnaldo Carvalho de Melo 
31*f12ad272SIan Rogers const char *input_name;
32*f12ad272SIan Rogers 
330a7c74eaSArnaldo Carvalho de Melo bool perf_singlethreaded = true;
340a7c74eaSArnaldo Carvalho de Melo 
perf_set_singlethreaded(void)350a7c74eaSArnaldo Carvalho de Melo void perf_set_singlethreaded(void)
360a7c74eaSArnaldo Carvalho de Melo {
370a7c74eaSArnaldo Carvalho de Melo 	perf_singlethreaded = true;
380a7c74eaSArnaldo Carvalho de Melo }
390a7c74eaSArnaldo Carvalho de Melo 
perf_set_multithreaded(void)400a7c74eaSArnaldo Carvalho de Melo void perf_set_multithreaded(void)
410a7c74eaSArnaldo Carvalho de Melo {
420a7c74eaSArnaldo Carvalho de Melo 	perf_singlethreaded = false;
430a7c74eaSArnaldo Carvalho de Melo }
440a7c74eaSArnaldo Carvalho de Melo 
45a29d5c9bSArnaldo Carvalho de Melo int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH;
46a29d5c9bSArnaldo Carvalho de Melo int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK;
474cb93446SArnaldo Carvalho de Melo 
sysctl__max_stack(void)48029c75e5SArnaldo Carvalho de Melo int sysctl__max_stack(void)
49029c75e5SArnaldo Carvalho de Melo {
50029c75e5SArnaldo Carvalho de Melo 	int value;
51029c75e5SArnaldo Carvalho de Melo 
52029c75e5SArnaldo Carvalho de Melo 	if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0)
53029c75e5SArnaldo Carvalho de Melo 		sysctl_perf_event_max_stack = value;
54029c75e5SArnaldo Carvalho de Melo 
55029c75e5SArnaldo Carvalho de Melo 	if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0)
56029c75e5SArnaldo Carvalho de Melo 		sysctl_perf_event_max_contexts_per_stack = value;
57029c75e5SArnaldo Carvalho de Melo 
58029c75e5SArnaldo Carvalho de Melo 	return sysctl_perf_event_max_stack;
59029c75e5SArnaldo Carvalho de Melo }
60029c75e5SArnaldo Carvalho de Melo 
sysctl__nmi_watchdog_enabled(void)612a14c1bfSKan Liang bool sysctl__nmi_watchdog_enabled(void)
622a14c1bfSKan Liang {
632a14c1bfSKan Liang 	static bool cached;
642a14c1bfSKan Liang 	static bool nmi_watchdog;
652a14c1bfSKan Liang 	int value;
662a14c1bfSKan Liang 
672a14c1bfSKan Liang 	if (cached)
682a14c1bfSKan Liang 		return nmi_watchdog;
692a14c1bfSKan Liang 
702a14c1bfSKan Liang 	if (sysctl__read_int("kernel/nmi_watchdog", &value) < 0)
712a14c1bfSKan Liang 		return false;
722a14c1bfSKan Liang 
732a14c1bfSKan Liang 	nmi_watchdog = (value > 0) ? true : false;
742a14c1bfSKan Liang 	cached = true;
752a14c1bfSKan Liang 
762a14c1bfSKan Liang 	return nmi_watchdog;
772a14c1bfSKan Liang }
782a14c1bfSKan Liang 
790c6332e9SArnaldo Carvalho de Melo bool test_attr__enabled;
800c6332e9SArnaldo Carvalho de Melo 
811aed2671SJoerg Roedel bool perf_host  = true;
82c4a7dca9SJoerg Roedel bool perf_guest = false;
831aed2671SJoerg Roedel 
event_attr_init(struct perf_event_attr * attr)841aed2671SJoerg Roedel void event_attr_init(struct perf_event_attr *attr)
851aed2671SJoerg Roedel {
861aed2671SJoerg Roedel 	if (!perf_host)
871aed2671SJoerg Roedel 		attr->exclude_host  = 1;
881aed2671SJoerg Roedel 	if (!perf_guest)
891aed2671SJoerg Roedel 		attr->exclude_guest = 1;
907e1ccd38SStephane Eranian 	/* to capture ABI version */
917e1ccd38SStephane Eranian 	attr->size = sizeof(*attr);
921aed2671SJoerg Roedel }
931aed2671SJoerg Roedel 
mkdir_p(char * path,mode_t mode)944cf40131SArnaldo Carvalho de Melo int mkdir_p(char *path, mode_t mode)
954cf40131SArnaldo Carvalho de Melo {
964cf40131SArnaldo Carvalho de Melo 	struct stat st;
974cf40131SArnaldo Carvalho de Melo 	int err;
984cf40131SArnaldo Carvalho de Melo 	char *d = path;
994cf40131SArnaldo Carvalho de Melo 
1004cf40131SArnaldo Carvalho de Melo 	if (*d != '/')
1014cf40131SArnaldo Carvalho de Melo 		return -1;
1024cf40131SArnaldo Carvalho de Melo 
1034cf40131SArnaldo Carvalho de Melo 	if (stat(path, &st) == 0)
1044cf40131SArnaldo Carvalho de Melo 		return 0;
1054cf40131SArnaldo Carvalho de Melo 
1064cf40131SArnaldo Carvalho de Melo 	while (*++d == '/');
1074cf40131SArnaldo Carvalho de Melo 
1084cf40131SArnaldo Carvalho de Melo 	while ((d = strchr(d, '/'))) {
1094cf40131SArnaldo Carvalho de Melo 		*d = '\0';
1104cf40131SArnaldo Carvalho de Melo 		err = stat(path, &st) && mkdir(path, mode);
1114cf40131SArnaldo Carvalho de Melo 		*d++ = '/';
1124cf40131SArnaldo Carvalho de Melo 		if (err)
1134cf40131SArnaldo Carvalho de Melo 			return -1;
1144cf40131SArnaldo Carvalho de Melo 		while (*d == '/')
1154cf40131SArnaldo Carvalho de Melo 			++d;
1164cf40131SArnaldo Carvalho de Melo 	}
1174cf40131SArnaldo Carvalho de Melo 	return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
1184cf40131SArnaldo Carvalho de Melo }
1194cf40131SArnaldo Carvalho de Melo 
match_pat(char * file,const char ** pat)120cdb6b023SJiri Olsa static bool match_pat(char *file, const char **pat)
121cdb6b023SJiri Olsa {
122cdb6b023SJiri Olsa 	int i = 0;
123cdb6b023SJiri Olsa 
124cdb6b023SJiri Olsa 	if (!pat)
125cdb6b023SJiri Olsa 		return true;
126cdb6b023SJiri Olsa 
127cdb6b023SJiri Olsa 	while (pat[i]) {
128cdb6b023SJiri Olsa 		if (strglobmatch(file, pat[i]))
129cdb6b023SJiri Olsa 			return true;
130cdb6b023SJiri Olsa 
131cdb6b023SJiri Olsa 		i++;
132cdb6b023SJiri Olsa 	}
133cdb6b023SJiri Olsa 
134cdb6b023SJiri Olsa 	return false;
135cdb6b023SJiri Olsa }
136cdb6b023SJiri Olsa 
13705a48659SJiri Olsa /*
13805a48659SJiri Olsa  * The depth specify how deep the removal will go.
13905a48659SJiri Olsa  * 0       - will remove only files under the 'path' directory
14005a48659SJiri Olsa  * 1 .. x  - will dive in x-level deep under the 'path' directory
141cdb6b023SJiri Olsa  *
142cdb6b023SJiri Olsa  * If specified the pat is array of string patterns ended with NULL,
143cdb6b023SJiri Olsa  * which are checked upon every file/directory found. Only matching
144cdb6b023SJiri Olsa  * ones are removed.
145cdb6b023SJiri Olsa  *
146cdb6b023SJiri Olsa  * The function returns:
147cdb6b023SJiri Olsa  *    0 on success
148cdb6b023SJiri Olsa  *   -1 on removal failure with errno set
149cdb6b023SJiri Olsa  *   -2 on pattern failure
15005a48659SJiri Olsa  */
rm_rf_depth_pat(const char * path,int depth,const char ** pat)151cdb6b023SJiri Olsa static int rm_rf_depth_pat(const char *path, int depth, const char **pat)
1520b1de0beSNamhyung Kim {
1530b1de0beSNamhyung Kim 	DIR *dir;
154b4409ae1SJiri Olsa 	int ret;
1550b1de0beSNamhyung Kim 	struct dirent *d;
1560b1de0beSNamhyung Kim 	char namebuf[PATH_MAX];
157b4409ae1SJiri Olsa 	struct stat statbuf;
1580b1de0beSNamhyung Kim 
159b4409ae1SJiri Olsa 	/* Do not fail if there's no file. */
160b4409ae1SJiri Olsa 	ret = lstat(path, &statbuf);
161b4409ae1SJiri Olsa 	if (ret)
1620b1de0beSNamhyung Kim 		return 0;
1630b1de0beSNamhyung Kim 
164b4409ae1SJiri Olsa 	/* Try to remove any file we get. */
165b4409ae1SJiri Olsa 	if (!(statbuf.st_mode & S_IFDIR))
166b4409ae1SJiri Olsa 		return unlink(path);
167b4409ae1SJiri Olsa 
168b4409ae1SJiri Olsa 	/* We have directory in path. */
169b4409ae1SJiri Olsa 	dir = opendir(path);
170b4409ae1SJiri Olsa 	if (dir == NULL)
171b4409ae1SJiri Olsa 		return -1;
172b4409ae1SJiri Olsa 
1730b1de0beSNamhyung Kim 	while ((d = readdir(dir)) != NULL && !ret) {
1740b1de0beSNamhyung Kim 
1750b1de0beSNamhyung Kim 		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
1760b1de0beSNamhyung Kim 			continue;
1770b1de0beSNamhyung Kim 
1786080728fSYunfeng Ye 		if (!match_pat(d->d_name, pat)) {
1796080728fSYunfeng Ye 			ret =  -2;
1806080728fSYunfeng Ye 			break;
1816080728fSYunfeng Ye 		}
182cdb6b023SJiri Olsa 
1830b1de0beSNamhyung Kim 		scnprintf(namebuf, sizeof(namebuf), "%s/%s",
1840b1de0beSNamhyung Kim 			  path, d->d_name);
1850b1de0beSNamhyung Kim 
1862a1ef032SMasami Hiramatsu 		/* We have to check symbolic link itself */
1872a1ef032SMasami Hiramatsu 		ret = lstat(namebuf, &statbuf);
1880b1de0beSNamhyung Kim 		if (ret < 0) {
1890b1de0beSNamhyung Kim 			pr_debug("stat failed: %s\n", namebuf);
1900b1de0beSNamhyung Kim 			break;
1910b1de0beSNamhyung Kim 		}
1920b1de0beSNamhyung Kim 
1932a1ef032SMasami Hiramatsu 		if (S_ISDIR(statbuf.st_mode))
194cdb6b023SJiri Olsa 			ret = depth ? rm_rf_depth_pat(namebuf, depth - 1, pat) : 0;
1952a1ef032SMasami Hiramatsu 		else
1962a1ef032SMasami Hiramatsu 			ret = unlink(namebuf);
1970b1de0beSNamhyung Kim 	}
1980b1de0beSNamhyung Kim 	closedir(dir);
1990b1de0beSNamhyung Kim 
2000b1de0beSNamhyung Kim 	if (ret < 0)
2010b1de0beSNamhyung Kim 		return ret;
2020b1de0beSNamhyung Kim 
2030b1de0beSNamhyung Kim 	return rmdir(path);
2040b1de0beSNamhyung Kim }
2050b1de0beSNamhyung Kim 
rm_rf_a_kcore_dir(const char * path,const char * name)206386e0d83SAdrian Hunter static int rm_rf_a_kcore_dir(const char *path, const char *name)
207eeb399b5SAdrian Hunter {
208eeb399b5SAdrian Hunter 	char kcore_dir_path[PATH_MAX];
209eeb399b5SAdrian Hunter 	const char *pat[] = {
210eeb399b5SAdrian Hunter 		"kcore",
211eeb399b5SAdrian Hunter 		"kallsyms",
212eeb399b5SAdrian Hunter 		"modules",
213eeb399b5SAdrian Hunter 		NULL,
214eeb399b5SAdrian Hunter 	};
215eeb399b5SAdrian Hunter 
216386e0d83SAdrian Hunter 	snprintf(kcore_dir_path, sizeof(kcore_dir_path), "%s/%s", path, name);
217eeb399b5SAdrian Hunter 
218eeb399b5SAdrian Hunter 	return rm_rf_depth_pat(kcore_dir_path, 0, pat);
219eeb399b5SAdrian Hunter }
220eeb399b5SAdrian Hunter 
kcore_dir_filter(const char * name __maybe_unused,struct dirent * d)221386e0d83SAdrian Hunter static bool kcore_dir_filter(const char *name __maybe_unused, struct dirent *d)
222386e0d83SAdrian Hunter {
223386e0d83SAdrian Hunter 	const char *pat[] = {
224386e0d83SAdrian Hunter 		"kcore_dir",
225386e0d83SAdrian Hunter 		"kcore_dir__[1-9]*",
226386e0d83SAdrian Hunter 		NULL,
227386e0d83SAdrian Hunter 	};
228386e0d83SAdrian Hunter 
229386e0d83SAdrian Hunter 	return match_pat(d->d_name, pat);
230386e0d83SAdrian Hunter }
231386e0d83SAdrian Hunter 
rm_rf_kcore_dir(const char * path)232386e0d83SAdrian Hunter static int rm_rf_kcore_dir(const char *path)
233386e0d83SAdrian Hunter {
234386e0d83SAdrian Hunter 	struct strlist *kcore_dirs;
235386e0d83SAdrian Hunter 	struct str_node *nd;
236386e0d83SAdrian Hunter 	int ret;
237386e0d83SAdrian Hunter 
238386e0d83SAdrian Hunter 	kcore_dirs = lsdir(path, kcore_dir_filter);
239386e0d83SAdrian Hunter 
240386e0d83SAdrian Hunter 	if (!kcore_dirs)
241386e0d83SAdrian Hunter 		return 0;
242386e0d83SAdrian Hunter 
243386e0d83SAdrian Hunter 	strlist__for_each_entry(nd, kcore_dirs) {
244386e0d83SAdrian Hunter 		ret = rm_rf_a_kcore_dir(path, nd->s);
245386e0d83SAdrian Hunter 		if (ret)
246386e0d83SAdrian Hunter 			return ret;
247386e0d83SAdrian Hunter 	}
248386e0d83SAdrian Hunter 
249386e0d83SAdrian Hunter 	strlist__delete(kcore_dirs);
250386e0d83SAdrian Hunter 
251386e0d83SAdrian Hunter 	return 0;
252386e0d83SAdrian Hunter }
253386e0d83SAdrian Hunter 
rm_rf_perf_data(const char * path)254c69e4c37SJiri Olsa int rm_rf_perf_data(const char *path)
255c69e4c37SJiri Olsa {
256c69e4c37SJiri Olsa 	const char *pat[] = {
2579b70b9dbSAdrian Hunter 		"data",
258c69e4c37SJiri Olsa 		"data.*",
259c69e4c37SJiri Olsa 		NULL,
260c69e4c37SJiri Olsa 	};
261c69e4c37SJiri Olsa 
262eeb399b5SAdrian Hunter 	rm_rf_kcore_dir(path);
263eeb399b5SAdrian Hunter 
264c69e4c37SJiri Olsa 	return rm_rf_depth_pat(path, 0, pat);
265c69e4c37SJiri Olsa }
266c69e4c37SJiri Olsa 
rm_rf(const char * path)26705a48659SJiri Olsa int rm_rf(const char *path)
26805a48659SJiri Olsa {
269cdb6b023SJiri Olsa 	return rm_rf_depth_pat(path, INT_MAX, NULL);
27005a48659SJiri Olsa }
27105a48659SJiri Olsa 
272e1ce726eSMasami Hiramatsu /* A filter which removes dot files */
lsdir_no_dot_filter(const char * name __maybe_unused,struct dirent * d)273e1ce726eSMasami Hiramatsu bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d)
274e1ce726eSMasami Hiramatsu {
275e1ce726eSMasami Hiramatsu 	return d->d_name[0] != '.';
276e1ce726eSMasami Hiramatsu }
277e1ce726eSMasami Hiramatsu 
278e1ce726eSMasami Hiramatsu /* lsdir reads a directory and store it in strlist */
lsdir(const char * name,bool (* filter)(const char *,struct dirent *))279e1ce726eSMasami Hiramatsu struct strlist *lsdir(const char *name,
280e1ce726eSMasami Hiramatsu 		      bool (*filter)(const char *, struct dirent *))
281e1ce726eSMasami Hiramatsu {
282e1ce726eSMasami Hiramatsu 	struct strlist *list = NULL;
283e1ce726eSMasami Hiramatsu 	DIR *dir;
284e1ce726eSMasami Hiramatsu 	struct dirent *d;
285e1ce726eSMasami Hiramatsu 
286e1ce726eSMasami Hiramatsu 	dir = opendir(name);
287e1ce726eSMasami Hiramatsu 	if (!dir)
288e1ce726eSMasami Hiramatsu 		return NULL;
289e1ce726eSMasami Hiramatsu 
290e1ce726eSMasami Hiramatsu 	list = strlist__new(NULL, NULL);
291e1ce726eSMasami Hiramatsu 	if (!list) {
292357a54f3SMasami Hiramatsu 		errno = ENOMEM;
293e1ce726eSMasami Hiramatsu 		goto out;
294e1ce726eSMasami Hiramatsu 	}
295e1ce726eSMasami Hiramatsu 
296e1ce726eSMasami Hiramatsu 	while ((d = readdir(dir)) != NULL) {
297e1ce726eSMasami Hiramatsu 		if (!filter || filter(name, d))
298e1ce726eSMasami Hiramatsu 			strlist__add(list, d->d_name);
299e1ce726eSMasami Hiramatsu 	}
300e1ce726eSMasami Hiramatsu 
301e1ce726eSMasami Hiramatsu out:
302e1ce726eSMasami Hiramatsu 	closedir(dir);
303e1ce726eSMasami Hiramatsu 	return list;
304e1ce726eSMasami Hiramatsu }
305e1ce726eSMasami Hiramatsu 
hex_width(u64 v)30661e04b33SArnaldo Carvalho de Melo size_t hex_width(u64 v)
30761e04b33SArnaldo Carvalho de Melo {
30861e04b33SArnaldo Carvalho de Melo 	size_t n = 1;
30961e04b33SArnaldo Carvalho de Melo 
31061e04b33SArnaldo Carvalho de Melo 	while ((v >>= 4))
31161e04b33SArnaldo Carvalho de Melo 		++n;
31261e04b33SArnaldo Carvalho de Melo 
31361e04b33SArnaldo Carvalho de Melo 	return n;
31461e04b33SArnaldo Carvalho de Melo }
315dc4552bfSArnaldo Carvalho de Melo 
perf_event_paranoid(void)3161a47245dSAdrian Hunter int perf_event_paranoid(void)
3171a47245dSAdrian Hunter {
3181a47245dSAdrian Hunter 	int value;
3191a47245dSAdrian Hunter 
320ce27309fSArnaldo Carvalho de Melo 	if (sysctl__read_int("kernel/perf_event_paranoid", &value))
3211a47245dSAdrian Hunter 		return INT_MAX;
3221a47245dSAdrian Hunter 
3231a47245dSAdrian Hunter 	return value;
3241a47245dSAdrian Hunter }
325c22e150eSIgor Lubashev 
perf_event_paranoid_check(int max_level)326c22e150eSIgor Lubashev bool perf_event_paranoid_check(int max_level)
327c22e150eSIgor Lubashev {
328c22e150eSIgor Lubashev 	return perf_cap__capable(CAP_SYS_ADMIN) ||
3296b3e0e2eSAlexey Budankov 			perf_cap__capable(CAP_PERFMON) ||
330c22e150eSIgor Lubashev 			perf_event_paranoid() <= max_level;
331c22e150eSIgor Lubashev }
332c22e150eSIgor Lubashev 
333d18acd15SWang Nan static int
fetch_ubuntu_kernel_version(unsigned int * puint)334d18acd15SWang Nan fetch_ubuntu_kernel_version(unsigned int *puint)
335d18acd15SWang Nan {
336d18acd15SWang Nan 	ssize_t len;
337d18acd15SWang Nan 	size_t line_len = 0;
338d18acd15SWang Nan 	char *ptr, *line = NULL;
339d18acd15SWang Nan 	int version, patchlevel, sublevel, err;
34044b58e06SArnaldo Carvalho de Melo 	FILE *vsig;
341d18acd15SWang Nan 
34244b58e06SArnaldo Carvalho de Melo 	if (!puint)
34344b58e06SArnaldo Carvalho de Melo 		return 0;
34444b58e06SArnaldo Carvalho de Melo 
34544b58e06SArnaldo Carvalho de Melo 	vsig = fopen("/proc/version_signature", "r");
346d18acd15SWang Nan 	if (!vsig) {
347d18acd15SWang Nan 		pr_debug("Open /proc/version_signature failed: %s\n",
348d18acd15SWang Nan 			 strerror(errno));
349d18acd15SWang Nan 		return -1;
350d18acd15SWang Nan 	}
351d18acd15SWang Nan 
352d18acd15SWang Nan 	len = getline(&line, &line_len, vsig);
353d18acd15SWang Nan 	fclose(vsig);
354d18acd15SWang Nan 	err = -1;
355d18acd15SWang Nan 	if (len <= 0) {
356d18acd15SWang Nan 		pr_debug("Reading from /proc/version_signature failed: %s\n",
357d18acd15SWang Nan 			 strerror(errno));
358d18acd15SWang Nan 		goto errout;
359d18acd15SWang Nan 	}
360d18acd15SWang Nan 
361d18acd15SWang Nan 	ptr = strrchr(line, ' ');
362d18acd15SWang Nan 	if (!ptr) {
363d18acd15SWang Nan 		pr_debug("Parsing /proc/version_signature failed: %s\n", line);
364d18acd15SWang Nan 		goto errout;
365d18acd15SWang Nan 	}
366d18acd15SWang Nan 
367d18acd15SWang Nan 	err = sscanf(ptr + 1, "%d.%d.%d",
368d18acd15SWang Nan 		     &version, &patchlevel, &sublevel);
369d18acd15SWang Nan 	if (err != 3) {
370d18acd15SWang Nan 		pr_debug("Unable to get kernel version from /proc/version_signature '%s'\n",
371d18acd15SWang Nan 			 line);
372d18acd15SWang Nan 		goto errout;
373d18acd15SWang Nan 	}
374d18acd15SWang Nan 
375d18acd15SWang Nan 	*puint = (version << 16) + (patchlevel << 8) + sublevel;
376d18acd15SWang Nan 	err = 0;
377d18acd15SWang Nan errout:
378d18acd15SWang Nan 	free(line);
379d18acd15SWang Nan 	return err;
380d18acd15SWang Nan }
381d18acd15SWang Nan 
38207bc5c69SWang Nan int
fetch_kernel_version(unsigned int * puint,char * str,size_t str_size)38307bc5c69SWang Nan fetch_kernel_version(unsigned int *puint, char *str,
38407bc5c69SWang Nan 		     size_t str_size)
38507bc5c69SWang Nan {
38607bc5c69SWang Nan 	struct utsname utsname;
38707bc5c69SWang Nan 	int version, patchlevel, sublevel, err;
388d18acd15SWang Nan 	bool int_ver_ready = false;
389d18acd15SWang Nan 
390d18acd15SWang Nan 	if (access("/proc/version_signature", R_OK) == 0)
391d18acd15SWang Nan 		if (!fetch_ubuntu_kernel_version(puint))
392d18acd15SWang Nan 			int_ver_ready = true;
39307bc5c69SWang Nan 
39407bc5c69SWang Nan 	if (uname(&utsname))
39507bc5c69SWang Nan 		return -1;
39607bc5c69SWang Nan 
39707bc5c69SWang Nan 	if (str && str_size) {
39807bc5c69SWang Nan 		strncpy(str, utsname.release, str_size);
39907bc5c69SWang Nan 		str[str_size - 1] = '\0';
40007bc5c69SWang Nan 	}
40107bc5c69SWang Nan 
40244b58e06SArnaldo Carvalho de Melo 	if (!puint || int_ver_ready)
40344b58e06SArnaldo Carvalho de Melo 		return 0;
40444b58e06SArnaldo Carvalho de Melo 
40507bc5c69SWang Nan 	err = sscanf(utsname.release, "%d.%d.%d",
40607bc5c69SWang Nan 		     &version, &patchlevel, &sublevel);
40707bc5c69SWang Nan 
40807bc5c69SWang Nan 	if (err != 3) {
409d18acd15SWang Nan 		pr_debug("Unable to get kernel version from uname '%s'\n",
41007bc5c69SWang Nan 			 utsname.release);
41107bc5c69SWang Nan 		return -1;
41207bc5c69SWang Nan 	}
41307bc5c69SWang Nan 
41407bc5c69SWang Nan 	*puint = (version << 16) + (patchlevel << 8) + sublevel;
41507bc5c69SWang Nan 	return 0;
41607bc5c69SWang Nan }
41714cbfbebSNamhyung Kim 
perf_tip(char ** strp,const char * dirpath)418d9fc7061SIan Rogers int perf_tip(char **strp, const char *dirpath)
41914cbfbebSNamhyung Kim {
42014cbfbebSNamhyung Kim 	struct strlist *tips;
42114cbfbebSNamhyung Kim 	struct str_node *node;
42214cbfbebSNamhyung Kim 	struct strlist_config conf = {
42334b7b0f9SNamhyung Kim 		.dirname = dirpath,
42434b7b0f9SNamhyung Kim 		.file_only = true,
42514cbfbebSNamhyung Kim 	};
426d9fc7061SIan Rogers 	int ret = 0;
42714cbfbebSNamhyung Kim 
428d9fc7061SIan Rogers 	*strp = NULL;
42914cbfbebSNamhyung Kim 	tips = strlist__new("tips.txt", &conf);
43034b7b0f9SNamhyung Kim 	if (tips == NULL)
431d9fc7061SIan Rogers 		return -errno;
43234b7b0f9SNamhyung Kim 
43334b7b0f9SNamhyung Kim 	if (strlist__nr_entries(tips) == 0)
43414cbfbebSNamhyung Kim 		goto out;
43514cbfbebSNamhyung Kim 
43614cbfbebSNamhyung Kim 	node = strlist__entry(tips, random() % strlist__nr_entries(tips));
437d9fc7061SIan Rogers 	if (asprintf(strp, "Tip: %s", node->s) < 0)
438d9fc7061SIan Rogers 		ret = -ENOMEM;
43914cbfbebSNamhyung Kim 
44014cbfbebSNamhyung Kim out:
44114cbfbebSNamhyung Kim 	strlist__delete(tips);
44214cbfbebSNamhyung Kim 
443d9fc7061SIan Rogers 	return ret;
44414cbfbebSNamhyung Kim }
44594816addSAndi Kleen 
perf_exe(char * buf,int len)44694816addSAndi Kleen char *perf_exe(char *buf, int len)
44794816addSAndi Kleen {
44894816addSAndi Kleen 	int n = readlink("/proc/self/exe", buf, len);
44994816addSAndi Kleen 	if (n > 0) {
45094816addSAndi Kleen 		buf[n] = 0;
45194816addSAndi Kleen 		return buf;
45294816addSAndi Kleen 	}
45394816addSAndi Kleen 	return strcpy(buf, "perf");
45494816addSAndi Kleen }
4559bce13eaSJiri Olsa 
perf_debuginfod_setup(struct perf_debuginfod * di)4569bce13eaSJiri Olsa void perf_debuginfod_setup(struct perf_debuginfod *di)
4579bce13eaSJiri Olsa {
4589bce13eaSJiri Olsa 	/*
4599bce13eaSJiri Olsa 	 * By default '!di->set' we clear DEBUGINFOD_URLS, so debuginfod
4609bce13eaSJiri Olsa 	 * processing is not triggered, otherwise we set it to 'di->urls'
4619bce13eaSJiri Olsa 	 * value. If 'di->urls' is "system" we keep DEBUGINFOD_URLS value.
4629bce13eaSJiri Olsa 	 */
4639bce13eaSJiri Olsa 	if (!di->set)
4649bce13eaSJiri Olsa 		setenv("DEBUGINFOD_URLS", "", 1);
4659bce13eaSJiri Olsa 	else if (di->urls && strcmp(di->urls, "system"))
4669bce13eaSJiri Olsa 		setenv("DEBUGINFOD_URLS", di->urls, 1);
4679bce13eaSJiri Olsa 
4689bce13eaSJiri Olsa 	pr_debug("DEBUGINFOD_URLS=%s\n", getenv("DEBUGINFOD_URLS"));
469c60664deSMartin Liška 
470c60664deSMartin Liška #ifndef HAVE_DEBUGINFOD_SUPPORT
471c60664deSMartin Liška 	if (di->set)
472c60664deSMartin Liška 		pr_warning("WARNING: debuginfod support requested, but perf is not built with it\n");
473c60664deSMartin Liška #endif
4749bce13eaSJiri Olsa }
47567fd1892SNamhyung Kim 
47667fd1892SNamhyung Kim /*
47767fd1892SNamhyung Kim  * Return a new filename prepended with task's root directory if it's in
47867fd1892SNamhyung Kim  * a chroot.  Callers should free the returned string.
47967fd1892SNamhyung Kim  */
filename_with_chroot(int pid,const char * filename)48067fd1892SNamhyung Kim char *filename_with_chroot(int pid, const char *filename)
48167fd1892SNamhyung Kim {
48267fd1892SNamhyung Kim 	char buf[PATH_MAX];
48367fd1892SNamhyung Kim 	char proc_root[32];
48467fd1892SNamhyung Kim 	char *new_name = NULL;
48567fd1892SNamhyung Kim 	int ret;
48667fd1892SNamhyung Kim 
48767fd1892SNamhyung Kim 	scnprintf(proc_root, sizeof(proc_root), "/proc/%d/root", pid);
48867fd1892SNamhyung Kim 	ret = readlink(proc_root, buf, sizeof(buf) - 1);
48967fd1892SNamhyung Kim 	if (ret <= 0)
49067fd1892SNamhyung Kim 		return NULL;
49167fd1892SNamhyung Kim 
49267fd1892SNamhyung Kim 	/* readlink(2) does not append a null byte to buf */
49367fd1892SNamhyung Kim 	buf[ret] = '\0';
49467fd1892SNamhyung Kim 
49567fd1892SNamhyung Kim 	if (!strcmp(buf, "/"))
49667fd1892SNamhyung Kim 		return NULL;
49767fd1892SNamhyung Kim 
49867fd1892SNamhyung Kim 	if (strstr(buf, "(deleted)"))
49967fd1892SNamhyung Kim 		return NULL;
50067fd1892SNamhyung Kim 
50167fd1892SNamhyung Kim 	if (asprintf(&new_name, "%s/%s", buf, filename) < 0)
50267fd1892SNamhyung Kim 		return NULL;
50367fd1892SNamhyung Kim 
50467fd1892SNamhyung Kim 	return new_name;
50567fd1892SNamhyung Kim }
50610d34700SAdrian Hunter 
50710d34700SAdrian Hunter /*
50810d34700SAdrian Hunter  * Reallocate an array *arr of size *arr_sz so that it is big enough to contain
50910d34700SAdrian Hunter  * x elements of size msz, initializing new entries to *init_val or zero if
51010d34700SAdrian Hunter  * init_val is NULL
51110d34700SAdrian Hunter  */
do_realloc_array_as_needed(void ** arr,size_t * arr_sz,size_t x,size_t msz,const void * init_val)51210d34700SAdrian Hunter int do_realloc_array_as_needed(void **arr, size_t *arr_sz, size_t x, size_t msz, const void *init_val)
51310d34700SAdrian Hunter {
51410d34700SAdrian Hunter 	size_t new_sz = *arr_sz;
51510d34700SAdrian Hunter 	void *new_arr;
51610d34700SAdrian Hunter 	size_t i;
51710d34700SAdrian Hunter 
51810d34700SAdrian Hunter 	if (!new_sz)
51910d34700SAdrian Hunter 		new_sz = msz >= 64 ? 1 : roundup(64, msz); /* Start with at least 64 bytes */
52010d34700SAdrian Hunter 	while (x >= new_sz) {
52110d34700SAdrian Hunter 		if (check_mul_overflow(new_sz, (size_t)2, &new_sz))
52210d34700SAdrian Hunter 			return -ENOMEM;
52310d34700SAdrian Hunter 	}
52410d34700SAdrian Hunter 	if (new_sz == *arr_sz)
52510d34700SAdrian Hunter 		return 0;
52610d34700SAdrian Hunter 	new_arr = calloc(new_sz, msz);
52710d34700SAdrian Hunter 	if (!new_arr)
52810d34700SAdrian Hunter 		return -ENOMEM;
529f5ceb159SAdrian Hunter 	if (*arr_sz)
53010d34700SAdrian Hunter 		memcpy(new_arr, *arr, *arr_sz * msz);
53110d34700SAdrian Hunter 	if (init_val) {
53210d34700SAdrian Hunter 		for (i = *arr_sz; i < new_sz; i++)
53310d34700SAdrian Hunter 			memcpy(new_arr + (i * msz), init_val, msz);
53410d34700SAdrian Hunter 	}
53510d34700SAdrian Hunter 	*arr = new_arr;
53610d34700SAdrian Hunter 	*arr_sz = new_sz;
53710d34700SAdrian Hunter 	return 0;
53810d34700SAdrian Hunter }
5390cd3142fSIan Rogers 
5400cd3142fSIan Rogers #ifndef HAVE_SCHED_GETCPU_SUPPORT
sched_getcpu(void)5410cd3142fSIan Rogers int sched_getcpu(void)
5420cd3142fSIan Rogers {
5430cd3142fSIan Rogers #ifdef __NR_getcpu
5440cd3142fSIan Rogers 	unsigned int cpu;
5450cd3142fSIan Rogers 	int err = syscall(__NR_getcpu, &cpu, NULL, NULL);
5460cd3142fSIan Rogers 
5470cd3142fSIan Rogers 	if (!err)
5480cd3142fSIan Rogers 		return cpu;
5490cd3142fSIan Rogers #else
5500cd3142fSIan Rogers 	errno = ENOSYS;
5510cd3142fSIan Rogers #endif
5520cd3142fSIan Rogers 	return -1;
5530cd3142fSIan Rogers }
5540cd3142fSIan Rogers #endif
555