projects/linux·blob master · refs

559 lines · 10.7 KiB

1// SPDX-License-Identifier: GPL-2.0
2#include "perf.h"
3#include "util.h"
4#include "debug.h"
5#include "event.h"
6#include <api/fs/fs.h>
7#include <sys/stat.h>
8#include <sys/utsname.h>
9#include <dirent.h>
10#include <fcntl.h>
11#include <inttypes.h>
12#include <signal.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <errno.h>
17#include <limits.h>
18#include <linux/capability.h>
19#include <linux/kernel.h>
20#include <linux/log2.h>
21#include <linux/time64.h>
22#include <linux/overflow.h>
23#include <unistd.h>
24#include "cap.h"
25#include "strlist.h"
26#include "string2.h"
27
28/*
29 * XXX We need to find a better place for these things...
30 */
31
32const char *input_name;
33
34bool perf_singlethreaded = true;
35
36void perf_set_singlethreaded(void)
37{
38 perf_singlethreaded = true;
39}
40
41void perf_set_multithreaded(void)
42{
43 perf_singlethreaded = false;
44}
45
46int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH;
47int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK;
48
49int sysctl__max_stack(void)
50{
51 int value;
52
53 if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0)
54 sysctl_perf_event_max_stack = value;
55
56 if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0)
57 sysctl_perf_event_max_contexts_per_stack = value;
58
59 return sysctl_perf_event_max_stack;
60}
61
62bool sysctl__nmi_watchdog_enabled(void)
63{
64 static bool cached;
65 static bool nmi_watchdog;
66 int value;
67
68 if (cached)
69 return nmi_watchdog;
70
71 if (sysctl__read_int("kernel/nmi_watchdog", &value) < 0)
72 return false;
73
74 nmi_watchdog = (value > 0) ? true : false;
75 cached = true;
76
77 return nmi_watchdog;
78}
79
80bool exclude_GH_default;
81
82bool perf_host = true;
83bool perf_guest = false;
84
85void event_attr_init(struct perf_event_attr *attr)
86{
87 /* to capture ABI version */
88 attr->size = sizeof(*attr);
89
90 if (!exclude_GH_default)
91 return;
92
93 if (!perf_host)
94 attr->exclude_host = 1;
95 if (!perf_guest)
96 attr->exclude_guest = 1;
97}
98
99int mkdir_p(char *path, mode_t mode)
100{
101 struct stat st;
102 int err;
103 char *d = path;
104
105 if (*d != '/')
106 return -1;
107
108 if (stat(path, &st) == 0)
109 return 0;
110
111 while (*++d == '/');
112
113 while ((d = strchr(d, '/'))) {
114 *d = '\0';
115 err = stat(path, &st) && mkdir(path, mode);
116 *d++ = '/';
117 if (err)
118 return -1;
119 while (*d == '/')
120 ++d;
121 }
122 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
123}
124
125static bool match_pat(char *file, const char **pat)
126{
127 int i = 0;
128
129 if (!pat)
130 return true;
131
132 while (pat[i]) {
133 if (strglobmatch(file, pat[i]))
134 return true;
135
136 i++;
137 }
138
139 return false;
140}
141
142/*
143 * The depth specify how deep the removal will go.
144 * 0 - will remove only files under the 'path' directory
145 * 1 .. x - will dive in x-level deep under the 'path' directory
146 *
147 * If specified the pat is array of string patterns ended with NULL,
148 * which are checked upon every file/directory found. Only matching
149 * ones are removed.
150 *
151 * The function returns:
152 * 0 on success
153 * -1 on removal failure with errno set
154 * -2 on pattern failure
155 */
156static int rm_rf_depth_pat(const char *path, int depth, const char **pat)
157{
158 DIR *dir;
159 int ret;
160 struct dirent *d;
161 char namebuf[PATH_MAX];
162 struct stat statbuf;
163
164 /* Do not fail if there's no file. */
165 ret = lstat(path, &statbuf);
166 if (ret)
167 return 0;
168
169 /* Try to remove any file we get. */
170 if (!(statbuf.st_mode & S_IFDIR))
171 return unlink(path);
172
173 /* We have directory in path. */
174 dir = opendir(path);
175 if (dir == NULL)
176 return -1;
177
178 while ((d = readdir(dir)) != NULL && !ret) {
179
180 if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
181 continue;
182
183 if (!match_pat(d->d_name, pat)) {
184 ret = -2;
185 break;
186 }
187
188 scnprintf(namebuf, sizeof(namebuf), "%s/%s",
189 path, d->d_name);
190
191 /* We have to check symbolic link itself */
192 ret = lstat(namebuf, &statbuf);
193 if (ret < 0) {
194 pr_debug("stat failed: %s\n", namebuf);
195 break;
196 }
197
198 if (S_ISDIR(statbuf.st_mode))
199 ret = depth ? rm_rf_depth_pat(namebuf, depth - 1, pat) : 0;
200 else
201 ret = unlink(namebuf);
202 }
203 closedir(dir);
204
205 if (ret < 0)
206 return ret;
207
208 return rmdir(path);
209}
210
211static int rm_rf_a_kcore_dir(const char *path, const char *name)
212{
213 char kcore_dir_path[PATH_MAX];
214 const char *pat[] = {
215 "kcore",
216 "kallsyms",
217 "modules",
218 NULL,
219 };
220
221 snprintf(kcore_dir_path, sizeof(kcore_dir_path), "%s/%s", path, name);
222
223 return rm_rf_depth_pat(kcore_dir_path, 0, pat);
224}
225
226static bool kcore_dir_filter(const char *name __maybe_unused, struct dirent *d)
227{
228 const char *pat[] = {
229 "kcore_dir",
230 "kcore_dir__[1-9]*",
231 NULL,
232 };
233
234 return match_pat(d->d_name, pat);
235}
236
237static int rm_rf_kcore_dir(const char *path)
238{
239 struct strlist *kcore_dirs;
240 struct str_node *nd;
241 int ret;
242
243 kcore_dirs = lsdir(path, kcore_dir_filter);
244
245 if (!kcore_dirs)
246 return 0;
247
248 strlist__for_each_entry(nd, kcore_dirs) {
249 ret = rm_rf_a_kcore_dir(path, nd->s);
250 if (ret)
251 return ret;
252 }
253
254 strlist__delete(kcore_dirs);
255
256 return 0;
257}
258
259void cpumask_to_cpulist(char *cpumask, char *cpulist)
260{
261 int i, j, bm_size, nbits;
262 int len = strlen(cpumask);
263 unsigned long *bm;
264 char cpus[MAX_NR_CPUS];
265
266 for (i = 0; i < len; i++) {
267 if (cpumask[i] == ',') {
268 for (j = i; j < len; j++)
269 cpumask[j] = cpumask[j + 1];
270 }
271 }
272
273 len = strlen(cpumask);
274 bm_size = (len + 15) / 16;
275 nbits = bm_size * 64;
276 if (nbits <= 0)
277 return;
278
279 bm = calloc(bm_size, sizeof(unsigned long));
280 if (!bm)
281 goto free_bm;
282
283 for (i = 0; i < bm_size; i++) {
284 char blk[17];
285 int blklen = len > 16 ? 16 : len;
286
287 strncpy(blk, cpumask + len - blklen, blklen);
288 blk[blklen] = '\0';
289 bm[i] = strtoul(blk, NULL, 16);
290 cpumask[len - blklen] = '\0';
291 len = strlen(cpumask);
292 }
293
294 bitmap_scnprintf(bm, nbits, cpus, sizeof(cpus));
295 strcpy(cpulist, cpus);
296
297free_bm:
298 free(bm);
299}
300
301void print_separator2(int pre_dash_cnt, const char *s, int post_dash_cnt)
302{
303 printf("%.*s%s%.*s\n", pre_dash_cnt, graph_dotted_line, s, post_dash_cnt,
304 graph_dotted_line);
305}
306
307int rm_rf_perf_data(const char *path)
308{
309 const char *pat[] = {
310 "data",
311 "data.*",
312 NULL,
313 };
314
315 rm_rf_kcore_dir(path);
316
317 return rm_rf_depth_pat(path, 0, pat);
318}
319
320int rm_rf(const char *path)
321{
322 return rm_rf_depth_pat(path, INT_MAX, NULL);
323}
324
325/* A filter which removes dot files */
326bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d)
327{
328 return d->d_name[0] != '.';
329}
330
331/* lsdir reads a directory and store it in strlist */
332struct strlist *lsdir(const char *name,
333 bool (*filter)(const char *, struct dirent *))
334{
335 struct strlist *list = NULL;
336 DIR *dir;
337 struct dirent *d;
338
339 dir = opendir(name);
340 if (!dir)
341 return NULL;
342
343 list = strlist__new(NULL, NULL);
344 if (!list) {
345 errno = ENOMEM;
346 goto out;
347 }
348
349 while ((d = readdir(dir)) != NULL) {
350 if (!filter || filter(name, d))
351 strlist__add(list, d->d_name);
352 }
353
354out:
355 closedir(dir);
356 return list;
357}
358
359size_t hex_width(u64 v)
360{
361 size_t n = 1;
362
363 while ((v >>= 4))
364 ++n;
365
366 return n;
367}
368
369int perf_event_paranoid(void)
370{
371 int value;
372
373 if (sysctl__read_int("kernel/perf_event_paranoid", &value))
374 return INT_MAX;
375
376 return value;
377}
378
379bool perf_event_paranoid_check(int max_level)
380{
381 return perf_cap__capable(CAP_SYS_ADMIN) ||
382 perf_cap__capable(CAP_PERFMON) ||
383 perf_event_paranoid() <= max_level;
384}
385
386int perf_tip(char **strp, const char *dirpath)
387{
388 struct strlist *tips;
389 struct str_node *node;
390 struct strlist_config conf = {
391 .dirname = dirpath,
392 .file_only = true,
393 };
394 int ret = 0;
395
396 *strp = NULL;
397 tips = strlist__new("tips.txt", &conf);
398 if (tips == NULL)
399 return -errno;
400
401 if (strlist__nr_entries(tips) == 0)
402 goto out;
403
404 node = strlist__entry(tips, random() % strlist__nr_entries(tips));
405 if (asprintf(strp, "Tip: %s", node->s) < 0)
406 ret = -ENOMEM;
407
408out:
409 strlist__delete(tips);
410
411 return ret;
412}
413
414char *perf_exe(char *buf, int len)
415{
416 int n;
417
418 if (len <= 0)
419 return buf;
420
421 n = readlink("/proc/self/exe", buf, len - 1);
422 if (n > 0) {
423 buf[n] = 0;
424 return buf;
425 }
426 if (len < (int)sizeof("perf")) {
427 buf[0] = '\0';
428 return buf;
429 }
430
431 return strcpy(buf, "perf");
432}
433
434void perf_debuginfod_setup(struct perf_debuginfod *di)
435{
436 /*
437 * By default '!di->set' we clear DEBUGINFOD_URLS, so debuginfod
438 * processing is not triggered, otherwise we set it to 'di->urls'
439 * value. If 'di->urls' is "system" we keep DEBUGINFOD_URLS value.
440 */
441 if (!di->set)
442 setenv("DEBUGINFOD_URLS", "", 1);
443 else if (di->urls && strcmp(di->urls, "system"))
444 setenv("DEBUGINFOD_URLS", di->urls, 1);
445
446 pr_debug("DEBUGINFOD_URLS=%s\n", getenv("DEBUGINFOD_URLS"));
447
448#ifndef HAVE_DEBUGINFOD_SUPPORT
449 if (di->set)
450 pr_warning("WARNING: debuginfod support requested, but perf is not built with it\n");
451#endif
452}
453
454/*
455 * Return a new filename prepended with task's root directory if it's in
456 * a chroot. Callers should free the returned string.
457 */
458char *filename_with_chroot(int pid, const char *filename)
459{
460 char buf[PATH_MAX];
461 char proc_root[32];
462 char *new_name = NULL;
463 int ret;
464
465 scnprintf(proc_root, sizeof(proc_root), "/proc/%d/root", pid);
466 ret = readlink(proc_root, buf, sizeof(buf) - 1);
467 if (ret <= 0)
468 return NULL;
469
470 /* readlink(2) does not append a null byte to buf */
471 buf[ret] = '\0';
472
473 if (!strcmp(buf, "/"))
474 return NULL;
475
476 if (strstr(buf, "(deleted)"))
477 return NULL;
478
479 if (asprintf(&new_name, "%s/%s", buf, filename) < 0)
480 return NULL;
481
482 return new_name;
483}
484
485/*
486 * Reallocate an array *arr of size *arr_sz so that it is big enough to contain
487 * x elements of size msz, initializing new entries to *init_val or zero if
488 * init_val is NULL
489 */
490int do_realloc_array_as_needed(void **arr, size_t *arr_sz, size_t x, size_t msz, const void *init_val)
491{
492 size_t new_sz = *arr_sz;
493 void *new_arr;
494 size_t i;
495
496 if (!new_sz)
497 new_sz = msz >= 64 ? 1 : roundup(64, msz); /* Start with at least 64 bytes */
498 while (x >= new_sz) {
499 if (check_mul_overflow(new_sz, (size_t)2, &new_sz))
500 return -ENOMEM;
501 }
502 if (new_sz == *arr_sz)
503 return 0;
504 new_arr = calloc(new_sz, msz);
505 if (!new_arr)
506 return -ENOMEM;
507 if (*arr_sz)
508 memcpy(new_arr, *arr, *arr_sz * msz);
509 if (init_val) {
510 for (i = *arr_sz; i < new_sz; i++)
511 memcpy(new_arr + (i * msz), init_val, msz);
512 }
513 *arr = new_arr;
514 *arr_sz = new_sz;
515 return 0;
516}
517
518#ifndef HAVE_SCHED_GETCPU_SUPPORT
519int sched_getcpu(void)
520{
521#ifdef __NR_getcpu
522 unsigned int cpu;
523 int err = syscall(__NR_getcpu, &cpu, NULL, NULL);
524
525 if (!err)
526 return cpu;
527#else
528 errno = ENOSYS;
529#endif
530 return -1;
531}
532#endif
533
534#ifndef HAVE_SCANDIRAT_SUPPORT
535int scandirat(int dirfd, const char *dirp,
536 struct dirent ***namelist,
537 int (*filter)(const struct dirent *),
538 int (*compar)(const struct dirent **, const struct dirent **))
539{
540 char path[PATH_MAX];
541 int err, fd = openat(dirfd, dirp, O_PATH);
542
543 if (fd < 0)
544 return fd;
545
546 snprintf(path, sizeof(path), "/proc/%d/fd/%d", getpid(), fd);
547 err = scandir(path, namelist, filter, compar);
548 close(fd);
549 return err;
550}
551#endif
552
553/* basename version that takes a const input string */
554const char *perf_basename(const char *path)
555{
556 const char *base = strrchr(path, '/');
557
558 return base ? base + 1 : path;
559}