Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include "util.h"
0003 #include "debug.h"
0004 #include "event.h"
0005 #include <api/fs/fs.h>
0006 #include <sys/stat.h>
0007 #include <sys/utsname.h>
0008 #include <dirent.h>
0009 #include <fcntl.h>
0010 #include <inttypes.h>
0011 #include <signal.h>
0012 #include <stdio.h>
0013 #include <stdlib.h>
0014 #include <string.h>
0015 #include <errno.h>
0016 #include <limits.h>
0017 #include <linux/capability.h>
0018 #include <linux/kernel.h>
0019 #include <linux/log2.h>
0020 #include <linux/time64.h>
0021 #include <linux/overflow.h>
0022 #include <unistd.h>
0023 #include "cap.h"
0024 #include "strlist.h"
0025 #include "string2.h"
0026 
0027 /*
0028  * XXX We need to find a better place for these things...
0029  */
0030 
0031 bool perf_singlethreaded = true;
0032 
0033 void perf_set_singlethreaded(void)
0034 {
0035     perf_singlethreaded = true;
0036 }
0037 
0038 void perf_set_multithreaded(void)
0039 {
0040     perf_singlethreaded = false;
0041 }
0042 
0043 int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH;
0044 int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK;
0045 
0046 int sysctl__max_stack(void)
0047 {
0048     int value;
0049 
0050     if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0)
0051         sysctl_perf_event_max_stack = value;
0052 
0053     if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0)
0054         sysctl_perf_event_max_contexts_per_stack = value;
0055 
0056     return sysctl_perf_event_max_stack;
0057 }
0058 
0059 bool sysctl__nmi_watchdog_enabled(void)
0060 {
0061     static bool cached;
0062     static bool nmi_watchdog;
0063     int value;
0064 
0065     if (cached)
0066         return nmi_watchdog;
0067 
0068     if (sysctl__read_int("kernel/nmi_watchdog", &value) < 0)
0069         return false;
0070 
0071     nmi_watchdog = (value > 0) ? true : false;
0072     cached = true;
0073 
0074     return nmi_watchdog;
0075 }
0076 
0077 bool test_attr__enabled;
0078 
0079 bool perf_host  = true;
0080 bool perf_guest = false;
0081 
0082 void event_attr_init(struct perf_event_attr *attr)
0083 {
0084     if (!perf_host)
0085         attr->exclude_host  = 1;
0086     if (!perf_guest)
0087         attr->exclude_guest = 1;
0088     /* to capture ABI version */
0089     attr->size = sizeof(*attr);
0090 }
0091 
0092 int mkdir_p(char *path, mode_t mode)
0093 {
0094     struct stat st;
0095     int err;
0096     char *d = path;
0097 
0098     if (*d != '/')
0099         return -1;
0100 
0101     if (stat(path, &st) == 0)
0102         return 0;
0103 
0104     while (*++d == '/');
0105 
0106     while ((d = strchr(d, '/'))) {
0107         *d = '\0';
0108         err = stat(path, &st) && mkdir(path, mode);
0109         *d++ = '/';
0110         if (err)
0111             return -1;
0112         while (*d == '/')
0113             ++d;
0114     }
0115     return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
0116 }
0117 
0118 static bool match_pat(char *file, const char **pat)
0119 {
0120     int i = 0;
0121 
0122     if (!pat)
0123         return true;
0124 
0125     while (pat[i]) {
0126         if (strglobmatch(file, pat[i]))
0127             return true;
0128 
0129         i++;
0130     }
0131 
0132     return false;
0133 }
0134 
0135 /*
0136  * The depth specify how deep the removal will go.
0137  * 0       - will remove only files under the 'path' directory
0138  * 1 .. x  - will dive in x-level deep under the 'path' directory
0139  *
0140  * If specified the pat is array of string patterns ended with NULL,
0141  * which are checked upon every file/directory found. Only matching
0142  * ones are removed.
0143  *
0144  * The function returns:
0145  *    0 on success
0146  *   -1 on removal failure with errno set
0147  *   -2 on pattern failure
0148  */
0149 static int rm_rf_depth_pat(const char *path, int depth, const char **pat)
0150 {
0151     DIR *dir;
0152     int ret;
0153     struct dirent *d;
0154     char namebuf[PATH_MAX];
0155     struct stat statbuf;
0156 
0157     /* Do not fail if there's no file. */
0158     ret = lstat(path, &statbuf);
0159     if (ret)
0160         return 0;
0161 
0162     /* Try to remove any file we get. */
0163     if (!(statbuf.st_mode & S_IFDIR))
0164         return unlink(path);
0165 
0166     /* We have directory in path. */
0167     dir = opendir(path);
0168     if (dir == NULL)
0169         return -1;
0170 
0171     while ((d = readdir(dir)) != NULL && !ret) {
0172 
0173         if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
0174             continue;
0175 
0176         if (!match_pat(d->d_name, pat)) {
0177             ret =  -2;
0178             break;
0179         }
0180 
0181         scnprintf(namebuf, sizeof(namebuf), "%s/%s",
0182               path, d->d_name);
0183 
0184         /* We have to check symbolic link itself */
0185         ret = lstat(namebuf, &statbuf);
0186         if (ret < 0) {
0187             pr_debug("stat failed: %s\n", namebuf);
0188             break;
0189         }
0190 
0191         if (S_ISDIR(statbuf.st_mode))
0192             ret = depth ? rm_rf_depth_pat(namebuf, depth - 1, pat) : 0;
0193         else
0194             ret = unlink(namebuf);
0195     }
0196     closedir(dir);
0197 
0198     if (ret < 0)
0199         return ret;
0200 
0201     return rmdir(path);
0202 }
0203 
0204 static int rm_rf_a_kcore_dir(const char *path, const char *name)
0205 {
0206     char kcore_dir_path[PATH_MAX];
0207     const char *pat[] = {
0208         "kcore",
0209         "kallsyms",
0210         "modules",
0211         NULL,
0212     };
0213 
0214     snprintf(kcore_dir_path, sizeof(kcore_dir_path), "%s/%s", path, name);
0215 
0216     return rm_rf_depth_pat(kcore_dir_path, 0, pat);
0217 }
0218 
0219 static bool kcore_dir_filter(const char *name __maybe_unused, struct dirent *d)
0220 {
0221     const char *pat[] = {
0222         "kcore_dir",
0223         "kcore_dir__[1-9]*",
0224         NULL,
0225     };
0226 
0227     return match_pat(d->d_name, pat);
0228 }
0229 
0230 static int rm_rf_kcore_dir(const char *path)
0231 {
0232     struct strlist *kcore_dirs;
0233     struct str_node *nd;
0234     int ret;
0235 
0236     kcore_dirs = lsdir(path, kcore_dir_filter);
0237 
0238     if (!kcore_dirs)
0239         return 0;
0240 
0241     strlist__for_each_entry(nd, kcore_dirs) {
0242         ret = rm_rf_a_kcore_dir(path, nd->s);
0243         if (ret)
0244             return ret;
0245     }
0246 
0247     strlist__delete(kcore_dirs);
0248 
0249     return 0;
0250 }
0251 
0252 int rm_rf_perf_data(const char *path)
0253 {
0254     const char *pat[] = {
0255         "data",
0256         "data.*",
0257         NULL,
0258     };
0259 
0260     rm_rf_kcore_dir(path);
0261 
0262     return rm_rf_depth_pat(path, 0, pat);
0263 }
0264 
0265 int rm_rf(const char *path)
0266 {
0267     return rm_rf_depth_pat(path, INT_MAX, NULL);
0268 }
0269 
0270 /* A filter which removes dot files */
0271 bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d)
0272 {
0273     return d->d_name[0] != '.';
0274 }
0275 
0276 /* lsdir reads a directory and store it in strlist */
0277 struct strlist *lsdir(const char *name,
0278               bool (*filter)(const char *, struct dirent *))
0279 {
0280     struct strlist *list = NULL;
0281     DIR *dir;
0282     struct dirent *d;
0283 
0284     dir = opendir(name);
0285     if (!dir)
0286         return NULL;
0287 
0288     list = strlist__new(NULL, NULL);
0289     if (!list) {
0290         errno = ENOMEM;
0291         goto out;
0292     }
0293 
0294     while ((d = readdir(dir)) != NULL) {
0295         if (!filter || filter(name, d))
0296             strlist__add(list, d->d_name);
0297     }
0298 
0299 out:
0300     closedir(dir);
0301     return list;
0302 }
0303 
0304 size_t hex_width(u64 v)
0305 {
0306     size_t n = 1;
0307 
0308     while ((v >>= 4))
0309         ++n;
0310 
0311     return n;
0312 }
0313 
0314 int perf_event_paranoid(void)
0315 {
0316     int value;
0317 
0318     if (sysctl__read_int("kernel/perf_event_paranoid", &value))
0319         return INT_MAX;
0320 
0321     return value;
0322 }
0323 
0324 bool perf_event_paranoid_check(int max_level)
0325 {
0326     return perf_cap__capable(CAP_SYS_ADMIN) ||
0327             perf_cap__capable(CAP_PERFMON) ||
0328             perf_event_paranoid() <= max_level;
0329 }
0330 
0331 static int
0332 fetch_ubuntu_kernel_version(unsigned int *puint)
0333 {
0334     ssize_t len;
0335     size_t line_len = 0;
0336     char *ptr, *line = NULL;
0337     int version, patchlevel, sublevel, err;
0338     FILE *vsig;
0339 
0340     if (!puint)
0341         return 0;
0342 
0343     vsig = fopen("/proc/version_signature", "r");
0344     if (!vsig) {
0345         pr_debug("Open /proc/version_signature failed: %s\n",
0346              strerror(errno));
0347         return -1;
0348     }
0349 
0350     len = getline(&line, &line_len, vsig);
0351     fclose(vsig);
0352     err = -1;
0353     if (len <= 0) {
0354         pr_debug("Reading from /proc/version_signature failed: %s\n",
0355              strerror(errno));
0356         goto errout;
0357     }
0358 
0359     ptr = strrchr(line, ' ');
0360     if (!ptr) {
0361         pr_debug("Parsing /proc/version_signature failed: %s\n", line);
0362         goto errout;
0363     }
0364 
0365     err = sscanf(ptr + 1, "%d.%d.%d",
0366              &version, &patchlevel, &sublevel);
0367     if (err != 3) {
0368         pr_debug("Unable to get kernel version from /proc/version_signature '%s'\n",
0369              line);
0370         goto errout;
0371     }
0372 
0373     *puint = (version << 16) + (patchlevel << 8) + sublevel;
0374     err = 0;
0375 errout:
0376     free(line);
0377     return err;
0378 }
0379 
0380 int
0381 fetch_kernel_version(unsigned int *puint, char *str,
0382              size_t str_size)
0383 {
0384     struct utsname utsname;
0385     int version, patchlevel, sublevel, err;
0386     bool int_ver_ready = false;
0387 
0388     if (access("/proc/version_signature", R_OK) == 0)
0389         if (!fetch_ubuntu_kernel_version(puint))
0390             int_ver_ready = true;
0391 
0392     if (uname(&utsname))
0393         return -1;
0394 
0395     if (str && str_size) {
0396         strncpy(str, utsname.release, str_size);
0397         str[str_size - 1] = '\0';
0398     }
0399 
0400     if (!puint || int_ver_ready)
0401         return 0;
0402 
0403     err = sscanf(utsname.release, "%d.%d.%d",
0404              &version, &patchlevel, &sublevel);
0405 
0406     if (err != 3) {
0407         pr_debug("Unable to get kernel version from uname '%s'\n",
0408              utsname.release);
0409         return -1;
0410     }
0411 
0412     *puint = (version << 16) + (patchlevel << 8) + sublevel;
0413     return 0;
0414 }
0415 
0416 int perf_tip(char **strp, const char *dirpath)
0417 {
0418     struct strlist *tips;
0419     struct str_node *node;
0420     struct strlist_config conf = {
0421         .dirname = dirpath,
0422         .file_only = true,
0423     };
0424     int ret = 0;
0425 
0426     *strp = NULL;
0427     tips = strlist__new("tips.txt", &conf);
0428     if (tips == NULL)
0429         return -errno;
0430 
0431     if (strlist__nr_entries(tips) == 0)
0432         goto out;
0433 
0434     node = strlist__entry(tips, random() % strlist__nr_entries(tips));
0435     if (asprintf(strp, "Tip: %s", node->s) < 0)
0436         ret = -ENOMEM;
0437 
0438 out:
0439     strlist__delete(tips);
0440 
0441     return ret;
0442 }
0443 
0444 char *perf_exe(char *buf, int len)
0445 {
0446     int n = readlink("/proc/self/exe", buf, len);
0447     if (n > 0) {
0448         buf[n] = 0;
0449         return buf;
0450     }
0451     return strcpy(buf, "perf");
0452 }
0453 
0454 void perf_debuginfod_setup(struct perf_debuginfod *di)
0455 {
0456     /*
0457      * By default '!di->set' we clear DEBUGINFOD_URLS, so debuginfod
0458      * processing is not triggered, otherwise we set it to 'di->urls'
0459      * value. If 'di->urls' is "system" we keep DEBUGINFOD_URLS value.
0460      */
0461     if (!di->set)
0462         setenv("DEBUGINFOD_URLS", "", 1);
0463     else if (di->urls && strcmp(di->urls, "system"))
0464         setenv("DEBUGINFOD_URLS", di->urls, 1);
0465 
0466     pr_debug("DEBUGINFOD_URLS=%s\n", getenv("DEBUGINFOD_URLS"));
0467 
0468 #ifndef HAVE_DEBUGINFOD_SUPPORT
0469     if (di->set)
0470         pr_warning("WARNING: debuginfod support requested, but perf is not built with it\n");
0471 #endif
0472 }
0473 
0474 /*
0475  * Return a new filename prepended with task's root directory if it's in
0476  * a chroot.  Callers should free the returned string.
0477  */
0478 char *filename_with_chroot(int pid, const char *filename)
0479 {
0480     char buf[PATH_MAX];
0481     char proc_root[32];
0482     char *new_name = NULL;
0483     int ret;
0484 
0485     scnprintf(proc_root, sizeof(proc_root), "/proc/%d/root", pid);
0486     ret = readlink(proc_root, buf, sizeof(buf) - 1);
0487     if (ret <= 0)
0488         return NULL;
0489 
0490     /* readlink(2) does not append a null byte to buf */
0491     buf[ret] = '\0';
0492 
0493     if (!strcmp(buf, "/"))
0494         return NULL;
0495 
0496     if (strstr(buf, "(deleted)"))
0497         return NULL;
0498 
0499     if (asprintf(&new_name, "%s/%s", buf, filename) < 0)
0500         return NULL;
0501 
0502     return new_name;
0503 }
0504 
0505 /*
0506  * Reallocate an array *arr of size *arr_sz so that it is big enough to contain
0507  * x elements of size msz, initializing new entries to *init_val or zero if
0508  * init_val is NULL
0509  */
0510 int do_realloc_array_as_needed(void **arr, size_t *arr_sz, size_t x, size_t msz, const void *init_val)
0511 {
0512     size_t new_sz = *arr_sz;
0513     void *new_arr;
0514     size_t i;
0515 
0516     if (!new_sz)
0517         new_sz = msz >= 64 ? 1 : roundup(64, msz); /* Start with at least 64 bytes */
0518     while (x >= new_sz) {
0519         if (check_mul_overflow(new_sz, (size_t)2, &new_sz))
0520             return -ENOMEM;
0521     }
0522     if (new_sz == *arr_sz)
0523         return 0;
0524     new_arr = calloc(new_sz, msz);
0525     if (!new_arr)
0526         return -ENOMEM;
0527     memcpy(new_arr, *arr, *arr_sz * msz);
0528     if (init_val) {
0529         for (i = *arr_sz; i < new_sz; i++)
0530             memcpy(new_arr + (i * msz), init_val, msz);
0531     }
0532     *arr = new_arr;
0533     *arr_sz = new_sz;
0534     return 0;
0535 }