1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 286470930SIngo Molnar /* 35f9273d6SNamhyung Kim * config.c 45f9273d6SNamhyung Kim * 55f9273d6SNamhyung Kim * Helper functions for parsing config items. 65f9273d6SNamhyung Kim * Originally copied from GIT source. 786470930SIngo Molnar * 886470930SIngo Molnar * Copyright (C) Linus Torvalds, 2005 986470930SIngo Molnar * Copyright (C) Johannes Schindelin, 2005 1086470930SIngo Molnar * 1186470930SIngo Molnar */ 12a43783aeSArnaldo Carvalho de Melo #include <errno.h> 13391e4206SArnaldo Carvalho de Melo #include <sys/param.h> 1486470930SIngo Molnar #include "cache.h" 15b10ba7f1SArnaldo Carvalho de Melo #include "callchain.h" 164b6ab94eSJosh Poimboeuf #include <subcmd/exec-cmd.h> 173fcb10e4SMark Drayton #include "util/event.h" /* proc_map_timeout */ 180b93da17SNamhyung Kim #include "util/hist.h" /* perf_hist_config */ 19aa61fd05SWang Nan #include "util/llvm-utils.h" /* perf_llvm_config */ 20d778a778SPaul A. Clarke #include "util/stat.h" /* perf_stat__set_big_num */ 21112cb561SSong Liu #include "util/evsel.h" /* evsel__hw_names, evsel__use_bpf_counters */ 224cb3c6d5SArnaldo Carvalho de Melo #include "build-id.h" 234cb3c6d5SArnaldo Carvalho de Melo #include "debug.h" 2420105ca1STaeung Song #include "config.h" 257a8ef4c4SArnaldo Carvalho de Melo #include <sys/types.h> 267a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h> 27f2a39fe8SArnaldo Carvalho de Melo #include <stdlib.h> 287a8ef4c4SArnaldo Carvalho de Melo #include <unistd.h> 298e99b6d4SArnaldo Carvalho de Melo #include <linux/string.h> 307f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 313052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h> 323d689ed6SArnaldo Carvalho de Melo 3386470930SIngo Molnar #define MAXNAME (256) 3486470930SIngo Molnar 3545de34bbSStephane Eranian #define DEBUG_CACHE_DIR ".debug" 3645de34bbSStephane Eranian 3745de34bbSStephane Eranian 3845de34bbSStephane Eranian char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */ 3945de34bbSStephane Eranian 4086470930SIngo Molnar static FILE *config_file; 4186470930SIngo Molnar static const char *config_file_name; 4286470930SIngo Molnar static int config_linenr; 4386470930SIngo Molnar static int config_file_eof; 448a0a9c7eSTaeung Song static struct perf_config_set *config_set; 4586470930SIngo Molnar 46c7ac2417STaeung Song const char *config_exclusive_filename; 4786470930SIngo Molnar 4886470930SIngo Molnar static int get_next_char(void) 4986470930SIngo Molnar { 5086470930SIngo Molnar int c; 5186470930SIngo Molnar FILE *f; 5286470930SIngo Molnar 5386470930SIngo Molnar c = '\n'; 5486470930SIngo Molnar if ((f = config_file) != NULL) { 5586470930SIngo Molnar c = fgetc(f); 5686470930SIngo Molnar if (c == '\r') { 5786470930SIngo Molnar /* DOS like systems */ 5886470930SIngo Molnar c = fgetc(f); 5986470930SIngo Molnar if (c != '\n') { 6086470930SIngo Molnar ungetc(c, f); 6186470930SIngo Molnar c = '\r'; 6286470930SIngo Molnar } 6386470930SIngo Molnar } 6486470930SIngo Molnar if (c == '\n') 6586470930SIngo Molnar config_linenr++; 6686470930SIngo Molnar if (c == EOF) { 6786470930SIngo Molnar config_file_eof = 1; 6886470930SIngo Molnar c = '\n'; 6986470930SIngo Molnar } 7086470930SIngo Molnar } 7186470930SIngo Molnar return c; 7286470930SIngo Molnar } 7386470930SIngo Molnar 7486470930SIngo Molnar static char *parse_value(void) 7586470930SIngo Molnar { 7686470930SIngo Molnar static char value[1024]; 77f37a291cSIngo Molnar int quote = 0, comment = 0, space = 0; 78f37a291cSIngo Molnar size_t len = 0; 7986470930SIngo Molnar 8086470930SIngo Molnar for (;;) { 8186470930SIngo Molnar int c = get_next_char(); 82f37a291cSIngo Molnar 8386470930SIngo Molnar if (len >= sizeof(value) - 1) 8486470930SIngo Molnar return NULL; 8586470930SIngo Molnar if (c == '\n') { 8686470930SIngo Molnar if (quote) 8786470930SIngo Molnar return NULL; 8886470930SIngo Molnar value[len] = 0; 8986470930SIngo Molnar return value; 9086470930SIngo Molnar } 9186470930SIngo Molnar if (comment) 9286470930SIngo Molnar continue; 9386470930SIngo Molnar if (isspace(c) && !quote) { 9486470930SIngo Molnar space = 1; 9586470930SIngo Molnar continue; 9686470930SIngo Molnar } 9786470930SIngo Molnar if (!quote) { 9886470930SIngo Molnar if (c == ';' || c == '#') { 9986470930SIngo Molnar comment = 1; 10086470930SIngo Molnar continue; 10186470930SIngo Molnar } 10286470930SIngo Molnar } 10386470930SIngo Molnar if (space) { 10486470930SIngo Molnar if (len) 10586470930SIngo Molnar value[len++] = ' '; 10686470930SIngo Molnar space = 0; 10786470930SIngo Molnar } 10886470930SIngo Molnar if (c == '\\') { 10986470930SIngo Molnar c = get_next_char(); 11086470930SIngo Molnar switch (c) { 11186470930SIngo Molnar case '\n': 11286470930SIngo Molnar continue; 11386470930SIngo Molnar case 't': 11486470930SIngo Molnar c = '\t'; 11586470930SIngo Molnar break; 11686470930SIngo Molnar case 'b': 11786470930SIngo Molnar c = '\b'; 11886470930SIngo Molnar break; 11986470930SIngo Molnar case 'n': 12086470930SIngo Molnar c = '\n'; 12186470930SIngo Molnar break; 12286470930SIngo Molnar /* Some characters escape as themselves */ 12386470930SIngo Molnar case '\\': case '"': 12486470930SIngo Molnar break; 12586470930SIngo Molnar /* Reject unknown escape sequences */ 12686470930SIngo Molnar default: 12786470930SIngo Molnar return NULL; 12886470930SIngo Molnar } 12986470930SIngo Molnar value[len++] = c; 13086470930SIngo Molnar continue; 13186470930SIngo Molnar } 13286470930SIngo Molnar if (c == '"') { 13386470930SIngo Molnar quote = 1-quote; 13486470930SIngo Molnar continue; 13586470930SIngo Molnar } 13686470930SIngo Molnar value[len++] = c; 13786470930SIngo Molnar } 13886470930SIngo Molnar } 13986470930SIngo Molnar 14086470930SIngo Molnar static inline int iskeychar(int c) 14186470930SIngo Molnar { 1428dc7c651SArnaldo Carvalho de Melo return isalnum(c) || c == '-' || c == '_'; 14386470930SIngo Molnar } 14486470930SIngo Molnar 14586470930SIngo Molnar static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) 14686470930SIngo Molnar { 14786470930SIngo Molnar int c; 14886470930SIngo Molnar char *value; 14986470930SIngo Molnar 15086470930SIngo Molnar /* Get the full name */ 15186470930SIngo Molnar for (;;) { 15286470930SIngo Molnar c = get_next_char(); 15386470930SIngo Molnar if (config_file_eof) 15486470930SIngo Molnar break; 15586470930SIngo Molnar if (!iskeychar(c)) 15686470930SIngo Molnar break; 15745de34bbSStephane Eranian name[len++] = c; 15886470930SIngo Molnar if (len >= MAXNAME) 15986470930SIngo Molnar return -1; 16086470930SIngo Molnar } 16186470930SIngo Molnar name[len] = 0; 16286470930SIngo Molnar while (c == ' ' || c == '\t') 16386470930SIngo Molnar c = get_next_char(); 16486470930SIngo Molnar 16586470930SIngo Molnar value = NULL; 16686470930SIngo Molnar if (c != '\n') { 16786470930SIngo Molnar if (c != '=') 16886470930SIngo Molnar return -1; 16986470930SIngo Molnar value = parse_value(); 17086470930SIngo Molnar if (!value) 17186470930SIngo Molnar return -1; 17286470930SIngo Molnar } 17386470930SIngo Molnar return fn(name, value, data); 17486470930SIngo Molnar } 17586470930SIngo Molnar 17686470930SIngo Molnar static int get_extended_base_var(char *name, int baselen, int c) 17786470930SIngo Molnar { 17886470930SIngo Molnar do { 17986470930SIngo Molnar if (c == '\n') 18086470930SIngo Molnar return -1; 18186470930SIngo Molnar c = get_next_char(); 18286470930SIngo Molnar } while (isspace(c)); 18386470930SIngo Molnar 18486470930SIngo Molnar /* We require the format to be '[base "extension"]' */ 18586470930SIngo Molnar if (c != '"') 18686470930SIngo Molnar return -1; 18786470930SIngo Molnar name[baselen++] = '.'; 18886470930SIngo Molnar 18986470930SIngo Molnar for (;;) { 19083a0944fSIngo Molnar int ch = get_next_char(); 19183a0944fSIngo Molnar 19283a0944fSIngo Molnar if (ch == '\n') 19386470930SIngo Molnar return -1; 19483a0944fSIngo Molnar if (ch == '"') 19586470930SIngo Molnar break; 19683a0944fSIngo Molnar if (ch == '\\') { 19783a0944fSIngo Molnar ch = get_next_char(); 19883a0944fSIngo Molnar if (ch == '\n') 19986470930SIngo Molnar return -1; 20086470930SIngo Molnar } 20183a0944fSIngo Molnar name[baselen++] = ch; 20286470930SIngo Molnar if (baselen > MAXNAME / 2) 20386470930SIngo Molnar return -1; 20486470930SIngo Molnar } 20586470930SIngo Molnar 20686470930SIngo Molnar /* Final ']' */ 20786470930SIngo Molnar if (get_next_char() != ']') 20886470930SIngo Molnar return -1; 20986470930SIngo Molnar return baselen; 21086470930SIngo Molnar } 21186470930SIngo Molnar 21286470930SIngo Molnar static int get_base_var(char *name) 21386470930SIngo Molnar { 21486470930SIngo Molnar int baselen = 0; 21586470930SIngo Molnar 21686470930SIngo Molnar for (;;) { 21786470930SIngo Molnar int c = get_next_char(); 21886470930SIngo Molnar if (config_file_eof) 21986470930SIngo Molnar return -1; 22086470930SIngo Molnar if (c == ']') 22186470930SIngo Molnar return baselen; 22286470930SIngo Molnar if (isspace(c)) 22386470930SIngo Molnar return get_extended_base_var(name, baselen, c); 22486470930SIngo Molnar if (!iskeychar(c) && c != '.') 22586470930SIngo Molnar return -1; 22686470930SIngo Molnar if (baselen > MAXNAME / 2) 22786470930SIngo Molnar return -1; 22886470930SIngo Molnar name[baselen++] = tolower(c); 22986470930SIngo Molnar } 23086470930SIngo Molnar } 23186470930SIngo Molnar 23286470930SIngo Molnar static int perf_parse_file(config_fn_t fn, void *data) 23386470930SIngo Molnar { 23486470930SIngo Molnar int comment = 0; 23586470930SIngo Molnar int baselen = 0; 23686470930SIngo Molnar static char var[MAXNAME]; 23786470930SIngo Molnar 23886470930SIngo Molnar /* U+FEFF Byte Order Mark in UTF8 */ 23986470930SIngo Molnar static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf"; 24086470930SIngo Molnar const unsigned char *bomptr = utf8_bom; 24186470930SIngo Molnar 24286470930SIngo Molnar for (;;) { 24349757c9cSJiri Olsa int line, c = get_next_char(); 24449757c9cSJiri Olsa 24586470930SIngo Molnar if (bomptr && *bomptr) { 24686470930SIngo Molnar /* We are at the file beginning; skip UTF8-encoded BOM 24786470930SIngo Molnar * if present. Sane editors won't put this in on their 24886470930SIngo Molnar * own, but e.g. Windows Notepad will do it happily. */ 24986470930SIngo Molnar if ((unsigned char) c == *bomptr) { 25086470930SIngo Molnar bomptr++; 25186470930SIngo Molnar continue; 25286470930SIngo Molnar } else { 25386470930SIngo Molnar /* Do not tolerate partial BOM. */ 25486470930SIngo Molnar if (bomptr != utf8_bom) 25586470930SIngo Molnar break; 25686470930SIngo Molnar /* No BOM at file beginning. Cool. */ 25786470930SIngo Molnar bomptr = NULL; 25886470930SIngo Molnar } 25986470930SIngo Molnar } 26086470930SIngo Molnar if (c == '\n') { 26186470930SIngo Molnar if (config_file_eof) 26286470930SIngo Molnar return 0; 26386470930SIngo Molnar comment = 0; 26486470930SIngo Molnar continue; 26586470930SIngo Molnar } 26686470930SIngo Molnar if (comment || isspace(c)) 26786470930SIngo Molnar continue; 26886470930SIngo Molnar if (c == '#' || c == ';') { 26986470930SIngo Molnar comment = 1; 27086470930SIngo Molnar continue; 27186470930SIngo Molnar } 27286470930SIngo Molnar if (c == '[') { 27386470930SIngo Molnar baselen = get_base_var(var); 27486470930SIngo Molnar if (baselen <= 0) 27586470930SIngo Molnar break; 27686470930SIngo Molnar var[baselen++] = '.'; 27786470930SIngo Molnar var[baselen] = 0; 27886470930SIngo Molnar continue; 27986470930SIngo Molnar } 28086470930SIngo Molnar if (!isalpha(c)) 28186470930SIngo Molnar break; 28286470930SIngo Molnar var[baselen] = tolower(c); 28349757c9cSJiri Olsa 28449757c9cSJiri Olsa /* 28549757c9cSJiri Olsa * The get_value function might or might not reach the '\n', 28649757c9cSJiri Olsa * so saving the current line number for error reporting. 28749757c9cSJiri Olsa */ 28849757c9cSJiri Olsa line = config_linenr; 28949757c9cSJiri Olsa if (get_value(fn, data, var, baselen+1) < 0) { 29049757c9cSJiri Olsa config_linenr = line; 29186470930SIngo Molnar break; 29286470930SIngo Molnar } 29349757c9cSJiri Olsa } 29478f71c99STaeung Song pr_err("bad config file line %d in %s\n", config_linenr, config_file_name); 29578f71c99STaeung Song return -1; 29686470930SIngo Molnar } 29786470930SIngo Molnar 29886470930SIngo Molnar static int parse_unit_factor(const char *end, unsigned long *val) 29986470930SIngo Molnar { 30086470930SIngo Molnar if (!*end) 30186470930SIngo Molnar return 1; 30286470930SIngo Molnar else if (!strcasecmp(end, "k")) { 30386470930SIngo Molnar *val *= 1024; 30486470930SIngo Molnar return 1; 30586470930SIngo Molnar } 30686470930SIngo Molnar else if (!strcasecmp(end, "m")) { 30786470930SIngo Molnar *val *= 1024 * 1024; 30886470930SIngo Molnar return 1; 30986470930SIngo Molnar } 31086470930SIngo Molnar else if (!strcasecmp(end, "g")) { 31186470930SIngo Molnar *val *= 1024 * 1024 * 1024; 31286470930SIngo Molnar return 1; 31386470930SIngo Molnar } 31486470930SIngo Molnar return 0; 31586470930SIngo Molnar } 31686470930SIngo Molnar 31794c0655fSJiri Olsa static int perf_parse_llong(const char *value, long long *ret) 31894c0655fSJiri Olsa { 31994c0655fSJiri Olsa if (value && *value) { 32094c0655fSJiri Olsa char *end; 32194c0655fSJiri Olsa long long val = strtoll(value, &end, 0); 32294c0655fSJiri Olsa unsigned long factor = 1; 32394c0655fSJiri Olsa 32494c0655fSJiri Olsa if (!parse_unit_factor(end, &factor)) 32594c0655fSJiri Olsa return 0; 32694c0655fSJiri Olsa *ret = val * factor; 32794c0655fSJiri Olsa return 1; 32894c0655fSJiri Olsa } 32994c0655fSJiri Olsa return 0; 33094c0655fSJiri Olsa } 33194c0655fSJiri Olsa 33286470930SIngo Molnar static int perf_parse_long(const char *value, long *ret) 33386470930SIngo Molnar { 33486470930SIngo Molnar if (value && *value) { 33586470930SIngo Molnar char *end; 33686470930SIngo Molnar long val = strtol(value, &end, 0); 33786470930SIngo Molnar unsigned long factor = 1; 33886470930SIngo Molnar if (!parse_unit_factor(end, &factor)) 33986470930SIngo Molnar return 0; 34086470930SIngo Molnar *ret = val * factor; 34186470930SIngo Molnar return 1; 34286470930SIngo Molnar } 34386470930SIngo Molnar return 0; 34486470930SIngo Molnar } 34586470930SIngo Molnar 34625ce4bb8SArnaldo Carvalho de Melo static void bad_config(const char *name) 34786470930SIngo Molnar { 34886470930SIngo Molnar if (config_file_name) 34925ce4bb8SArnaldo Carvalho de Melo pr_warning("bad config value for '%s' in %s, ignoring...\n", name, config_file_name); 35025ce4bb8SArnaldo Carvalho de Melo else 35125ce4bb8SArnaldo Carvalho de Melo pr_warning("bad config value for '%s', ignoring...\n", name); 35286470930SIngo Molnar } 35386470930SIngo Molnar 35425ce4bb8SArnaldo Carvalho de Melo int perf_config_u64(u64 *dest, const char *name, const char *value) 35594c0655fSJiri Olsa { 35694c0655fSJiri Olsa long long ret = 0; 35794c0655fSJiri Olsa 35825ce4bb8SArnaldo Carvalho de Melo if (!perf_parse_llong(value, &ret)) { 35925ce4bb8SArnaldo Carvalho de Melo bad_config(name); 36025ce4bb8SArnaldo Carvalho de Melo return -1; 36194c0655fSJiri Olsa } 36294c0655fSJiri Olsa 36325ce4bb8SArnaldo Carvalho de Melo *dest = ret; 36425ce4bb8SArnaldo Carvalho de Melo return 0; 36525ce4bb8SArnaldo Carvalho de Melo } 36625ce4bb8SArnaldo Carvalho de Melo 36725ce4bb8SArnaldo Carvalho de Melo int perf_config_int(int *dest, const char *name, const char *value) 36886470930SIngo Molnar { 36986470930SIngo Molnar long ret = 0; 37025ce4bb8SArnaldo Carvalho de Melo if (!perf_parse_long(value, &ret)) { 37125ce4bb8SArnaldo Carvalho de Melo bad_config(name); 37225ce4bb8SArnaldo Carvalho de Melo return -1; 37325ce4bb8SArnaldo Carvalho de Melo } 37425ce4bb8SArnaldo Carvalho de Melo *dest = ret; 37525ce4bb8SArnaldo Carvalho de Melo return 0; 37686470930SIngo Molnar } 37786470930SIngo Molnar 3787b43b697SRavi Bangoria int perf_config_u8(u8 *dest, const char *name, const char *value) 3797b43b697SRavi Bangoria { 3807b43b697SRavi Bangoria long ret = 0; 3817b43b697SRavi Bangoria 3827b43b697SRavi Bangoria if (!perf_parse_long(value, &ret)) { 3837b43b697SRavi Bangoria bad_config(name); 3847b43b697SRavi Bangoria return -1; 3857b43b697SRavi Bangoria } 3867b43b697SRavi Bangoria *dest = ret; 3877b43b697SRavi Bangoria return 0; 3887b43b697SRavi Bangoria } 3897b43b697SRavi Bangoria 390a41794cdSArnaldo Carvalho de Melo static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) 39186470930SIngo Molnar { 39225ce4bb8SArnaldo Carvalho de Melo int ret; 39325ce4bb8SArnaldo Carvalho de Melo 39486470930SIngo Molnar *is_bool = 1; 39586470930SIngo Molnar if (!value) 39686470930SIngo Molnar return 1; 39786470930SIngo Molnar if (!*value) 39886470930SIngo Molnar return 0; 39986470930SIngo Molnar if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on")) 40086470930SIngo Molnar return 1; 40186470930SIngo Molnar if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) 40286470930SIngo Molnar return 0; 40386470930SIngo Molnar *is_bool = 0; 40425ce4bb8SArnaldo Carvalho de Melo return perf_config_int(&ret, name, value) < 0 ? -1 : ret; 40586470930SIngo Molnar } 40686470930SIngo Molnar 40786470930SIngo Molnar int perf_config_bool(const char *name, const char *value) 40886470930SIngo Molnar { 40986470930SIngo Molnar int discard; 41086470930SIngo Molnar return !!perf_config_bool_or_int(name, value, &discard); 41186470930SIngo Molnar } 41286470930SIngo Molnar 413814b3f51SArnaldo Carvalho de Melo static const char *perf_config_dirname(const char *name, const char *value) 41445de34bbSStephane Eranian { 41545de34bbSStephane Eranian if (!name) 41645de34bbSStephane Eranian return NULL; 41745de34bbSStephane Eranian return value; 41845de34bbSStephane Eranian } 41945de34bbSStephane Eranian 4209cb5987cSTaeung Song static int perf_buildid_config(const char *var, const char *value) 4219cb5987cSTaeung Song { 4229cb5987cSTaeung Song /* same dir for all commands */ 4239cb5987cSTaeung Song if (!strcmp(var, "buildid.dir")) { 424d8e28654SVinson Lee const char *dir = perf_config_dirname(var, value); 4259cb5987cSTaeung Song 426ecc4c561SArnaldo Carvalho de Melo if (!dir) { 427ecc4c561SArnaldo Carvalho de Melo pr_err("Invalid buildid directory!\n"); 4289cb5987cSTaeung Song return -1; 429ecc4c561SArnaldo Carvalho de Melo } 430d8e28654SVinson Lee strncpy(buildid_dir, dir, MAXPATHLEN-1); 4319cb5987cSTaeung Song buildid_dir[MAXPATHLEN-1] = '\0'; 4329cb5987cSTaeung Song } 4339cb5987cSTaeung Song 4349cb5987cSTaeung Song return 0; 4359cb5987cSTaeung Song } 4369cb5987cSTaeung Song 4371d037ca1SIrina Tirdea static int perf_default_core_config(const char *var __maybe_unused, 4381d037ca1SIrina Tirdea const char *value __maybe_unused) 43986470930SIngo Molnar { 4403fcb10e4SMark Drayton if (!strcmp(var, "core.proc-map-timeout")) 4413fcb10e4SMark Drayton proc_map_timeout = strtoul(value, NULL, 10); 4423fcb10e4SMark Drayton 443395cf969SPaul Bolle /* Add other config variables here. */ 44486470930SIngo Molnar return 0; 44586470930SIngo Molnar } 44686470930SIngo Molnar 447c8302367SJiri Olsa static int perf_ui_config(const char *var, const char *value) 448c8302367SJiri Olsa { 449c8302367SJiri Olsa /* Add other config variables here. */ 450ecc4c561SArnaldo Carvalho de Melo if (!strcmp(var, "ui.show-headers")) 451c8302367SJiri Olsa symbol_conf.show_hist_headers = perf_config_bool(var, value); 452ecc4c561SArnaldo Carvalho de Melo 453c8302367SJiri Olsa return 0; 454c8302367SJiri Olsa } 455c8302367SJiri Olsa 456d778a778SPaul A. Clarke static int perf_stat_config(const char *var, const char *value) 457d778a778SPaul A. Clarke { 458d778a778SPaul A. Clarke if (!strcmp(var, "stat.big-num")) 459d778a778SPaul A. Clarke perf_stat__set_big_num(perf_config_bool(var, value)); 460d778a778SPaul A. Clarke 4610bdad978SJin Yao if (!strcmp(var, "stat.no-csv-summary")) 4620bdad978SJin Yao perf_stat__set_no_csv_summary(perf_config_bool(var, value)); 4630bdad978SJin Yao 464112cb561SSong Liu if (!strcmp(var, "stat.bpf-counter-events")) 465112cb561SSong Liu evsel__bpf_counter_events = strdup(value); 466112cb561SSong Liu 467d778a778SPaul A. Clarke /* Add other config variables here. */ 468d778a778SPaul A. Clarke return 0; 469d778a778SPaul A. Clarke } 470d778a778SPaul A. Clarke 4711d037ca1SIrina Tirdea int perf_default_config(const char *var, const char *value, 4721d037ca1SIrina Tirdea void *dummy __maybe_unused) 47386470930SIngo Molnar { 4748e99b6d4SArnaldo Carvalho de Melo if (strstarts(var, "core.")) 47586470930SIngo Molnar return perf_default_core_config(var, value); 47686470930SIngo Molnar 4778e99b6d4SArnaldo Carvalho de Melo if (strstarts(var, "hist.")) 4780b93da17SNamhyung Kim return perf_hist_config(var, value); 4790b93da17SNamhyung Kim 4808e99b6d4SArnaldo Carvalho de Melo if (strstarts(var, "ui.")) 481c8302367SJiri Olsa return perf_ui_config(var, value); 482c8302367SJiri Olsa 4838e99b6d4SArnaldo Carvalho de Melo if (strstarts(var, "call-graph.")) 4842b9240caSNamhyung Kim return perf_callchain_config(var, value); 4852b9240caSNamhyung Kim 4868e99b6d4SArnaldo Carvalho de Melo if (strstarts(var, "llvm.")) 487aa61fd05SWang Nan return perf_llvm_config(var, value); 488aa61fd05SWang Nan 4898e99b6d4SArnaldo Carvalho de Melo if (strstarts(var, "buildid.")) 4909cb5987cSTaeung Song return perf_buildid_config(var, value); 4919cb5987cSTaeung Song 492d778a778SPaul A. Clarke if (strstarts(var, "stat.")) 493d778a778SPaul A. Clarke return perf_stat_config(var, value); 494d778a778SPaul A. Clarke 495395cf969SPaul Bolle /* Add other config variables here. */ 49686470930SIngo Molnar return 0; 49786470930SIngo Molnar } 49886470930SIngo Molnar 49964b9705bSJiri Olsa static int perf_config_from_file(config_fn_t fn, const char *filename, void *data) 50086470930SIngo Molnar { 50186470930SIngo Molnar int ret; 50286470930SIngo Molnar FILE *f = fopen(filename, "r"); 50386470930SIngo Molnar 50486470930SIngo Molnar ret = -1; 50586470930SIngo Molnar if (f) { 50686470930SIngo Molnar config_file = f; 50786470930SIngo Molnar config_file_name = filename; 50886470930SIngo Molnar config_linenr = 1; 50986470930SIngo Molnar config_file_eof = 0; 51086470930SIngo Molnar ret = perf_parse_file(fn, data); 51186470930SIngo Molnar fclose(f); 51286470930SIngo Molnar config_file_name = NULL; 51386470930SIngo Molnar } 51486470930SIngo Molnar return ret; 51586470930SIngo Molnar } 51686470930SIngo Molnar 517c7ac2417STaeung Song const char *perf_etc_perfconfig(void) 51886470930SIngo Molnar { 51986470930SIngo Molnar static const char *system_wide; 52086470930SIngo Molnar if (!system_wide) 52186470930SIngo Molnar system_wide = system_path(ETC_PERFCONFIG); 52286470930SIngo Molnar return system_wide; 52386470930SIngo Molnar } 52486470930SIngo Molnar 52586470930SIngo Molnar static int perf_env_bool(const char *k, int def) 52686470930SIngo Molnar { 52786470930SIngo Molnar const char *v = getenv(k); 52886470930SIngo Molnar return v ? perf_config_bool(k, v) : def; 52986470930SIngo Molnar } 53086470930SIngo Molnar 531b2946282SJiri Olsa int perf_config_system(void) 53286470930SIngo Molnar { 53386470930SIngo Molnar return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0); 53486470930SIngo Molnar } 53586470930SIngo Molnar 536e8b2db07SJiri Olsa int perf_config_global(void) 53786470930SIngo Molnar { 53886470930SIngo Molnar return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); 53986470930SIngo Molnar } 54086470930SIngo Molnar 541f5f03e19SJiri Olsa static char *home_perfconfig(void) 542f5f03e19SJiri Olsa { 543f5f03e19SJiri Olsa const char *home = NULL; 544f5f03e19SJiri Olsa char *config; 545f5f03e19SJiri Olsa struct stat st; 546f5f03e19SJiri Olsa 547f5f03e19SJiri Olsa home = getenv("HOME"); 548f5f03e19SJiri Olsa 549f5f03e19SJiri Olsa /* 550f5f03e19SJiri Olsa * Skip reading user config if: 551f5f03e19SJiri Olsa * - there is no place to read it from (HOME) 552f5f03e19SJiri Olsa * - we are asked not to (PERF_CONFIG_NOGLOBAL=1) 553f5f03e19SJiri Olsa */ 554f5f03e19SJiri Olsa if (!home || !*home || !perf_config_global()) 555f5f03e19SJiri Olsa return NULL; 556f5f03e19SJiri Olsa 557f5f03e19SJiri Olsa config = strdup(mkpath("%s/.perfconfig", home)); 558f5f03e19SJiri Olsa if (config == NULL) { 559f5f03e19SJiri Olsa pr_warning("Not enough memory to process %s/.perfconfig, ignoring it.", home); 560f5f03e19SJiri Olsa return NULL; 561f5f03e19SJiri Olsa } 562f5f03e19SJiri Olsa 563f5f03e19SJiri Olsa if (stat(config, &st) < 0) 564f5f03e19SJiri Olsa goto out_free; 565f5f03e19SJiri Olsa 566f5f03e19SJiri Olsa if (st.st_uid && (st.st_uid != geteuid())) { 567f5f03e19SJiri Olsa pr_warning("File %s not owned by current user or root, ignoring it.", config); 568f5f03e19SJiri Olsa goto out_free; 569f5f03e19SJiri Olsa } 570f5f03e19SJiri Olsa 571f5f03e19SJiri Olsa if (st.st_size) 572f5f03e19SJiri Olsa return config; 573f5f03e19SJiri Olsa 574f5f03e19SJiri Olsa out_free: 575f5f03e19SJiri Olsa free(config); 576f5f03e19SJiri Olsa return NULL; 577f5f03e19SJiri Olsa } 578f5f03e19SJiri Olsa 579f5f03e19SJiri Olsa const char *perf_home_perfconfig(void) 580f5f03e19SJiri Olsa { 581f5f03e19SJiri Olsa static const char *config; 582f5f03e19SJiri Olsa static bool failed; 583f5f03e19SJiri Olsa 584*261f4911SArnaldo Carvalho de Melo if (failed || config) 585*261f4911SArnaldo Carvalho de Melo return config; 586*261f4911SArnaldo Carvalho de Melo 587*261f4911SArnaldo Carvalho de Melo config = home_perfconfig(); 588f5f03e19SJiri Olsa if (!config) 589f5f03e19SJiri Olsa failed = true; 590f5f03e19SJiri Olsa 591f5f03e19SJiri Olsa return config; 592f5f03e19SJiri Olsa } 593f5f03e19SJiri Olsa 59420105ca1STaeung Song static struct perf_config_section *find_section(struct list_head *sections, 59520105ca1STaeung Song const char *section_name) 59620105ca1STaeung Song { 59720105ca1STaeung Song struct perf_config_section *section; 59820105ca1STaeung Song 59920105ca1STaeung Song list_for_each_entry(section, sections, node) 60020105ca1STaeung Song if (!strcmp(section->name, section_name)) 60120105ca1STaeung Song return section; 60220105ca1STaeung Song 60320105ca1STaeung Song return NULL; 60420105ca1STaeung Song } 60520105ca1STaeung Song 60620105ca1STaeung Song static struct perf_config_item *find_config_item(const char *name, 60720105ca1STaeung Song struct perf_config_section *section) 60820105ca1STaeung Song { 60920105ca1STaeung Song struct perf_config_item *item; 61020105ca1STaeung Song 61120105ca1STaeung Song list_for_each_entry(item, §ion->items, node) 61220105ca1STaeung Song if (!strcmp(item->name, name)) 61320105ca1STaeung Song return item; 61420105ca1STaeung Song 61520105ca1STaeung Song return NULL; 61620105ca1STaeung Song } 61720105ca1STaeung Song 61820105ca1STaeung Song static struct perf_config_section *add_section(struct list_head *sections, 61920105ca1STaeung Song const char *section_name) 62020105ca1STaeung Song { 62120105ca1STaeung Song struct perf_config_section *section = zalloc(sizeof(*section)); 62220105ca1STaeung Song 62320105ca1STaeung Song if (!section) 62420105ca1STaeung Song return NULL; 62520105ca1STaeung Song 62620105ca1STaeung Song INIT_LIST_HEAD(§ion->items); 62720105ca1STaeung Song section->name = strdup(section_name); 62820105ca1STaeung Song if (!section->name) { 62920105ca1STaeung Song pr_debug("%s: strdup failed\n", __func__); 63020105ca1STaeung Song free(section); 63120105ca1STaeung Song return NULL; 63220105ca1STaeung Song } 63320105ca1STaeung Song 63420105ca1STaeung Song list_add_tail(§ion->node, sections); 63520105ca1STaeung Song return section; 63620105ca1STaeung Song } 63720105ca1STaeung Song 63820105ca1STaeung Song static struct perf_config_item *add_config_item(struct perf_config_section *section, 63920105ca1STaeung Song const char *name) 64020105ca1STaeung Song { 64120105ca1STaeung Song struct perf_config_item *item = zalloc(sizeof(*item)); 64220105ca1STaeung Song 64320105ca1STaeung Song if (!item) 64420105ca1STaeung Song return NULL; 64520105ca1STaeung Song 64620105ca1STaeung Song item->name = strdup(name); 64720105ca1STaeung Song if (!item->name) { 64820105ca1STaeung Song pr_debug("%s: strdup failed\n", __func__); 64920105ca1STaeung Song free(item); 65020105ca1STaeung Song return NULL; 65120105ca1STaeung Song } 65220105ca1STaeung Song 65320105ca1STaeung Song list_add_tail(&item->node, §ion->items); 65420105ca1STaeung Song return item; 65520105ca1STaeung Song } 65620105ca1STaeung Song 65720105ca1STaeung Song static int set_value(struct perf_config_item *item, const char *value) 65820105ca1STaeung Song { 65920105ca1STaeung Song char *val = strdup(value); 66020105ca1STaeung Song 66120105ca1STaeung Song if (!val) 66220105ca1STaeung Song return -1; 66320105ca1STaeung Song 66420105ca1STaeung Song zfree(&item->value); 66520105ca1STaeung Song item->value = val; 66620105ca1STaeung Song return 0; 66720105ca1STaeung Song } 66820105ca1STaeung Song 66920105ca1STaeung Song static int collect_config(const char *var, const char *value, 67020105ca1STaeung Song void *perf_config_set) 67120105ca1STaeung Song { 67220105ca1STaeung Song int ret = -1; 67320105ca1STaeung Song char *ptr, *key; 67420105ca1STaeung Song char *section_name, *name; 67520105ca1STaeung Song struct perf_config_section *section = NULL; 67620105ca1STaeung Song struct perf_config_item *item = NULL; 67720105ca1STaeung Song struct perf_config_set *set = perf_config_set; 6787db91f25STaeung Song struct list_head *sections; 67920105ca1STaeung Song 6807db91f25STaeung Song if (set == NULL) 6817db91f25STaeung Song return -1; 6827db91f25STaeung Song 6837db91f25STaeung Song sections = &set->sections; 68420105ca1STaeung Song key = ptr = strdup(var); 68520105ca1STaeung Song if (!key) { 68620105ca1STaeung Song pr_debug("%s: strdup failed\n", __func__); 68720105ca1STaeung Song return -1; 68820105ca1STaeung Song } 68920105ca1STaeung Song 69020105ca1STaeung Song section_name = strsep(&ptr, "."); 69120105ca1STaeung Song name = ptr; 69220105ca1STaeung Song if (name == NULL || value == NULL) 69320105ca1STaeung Song goto out_free; 69420105ca1STaeung Song 69520105ca1STaeung Song section = find_section(sections, section_name); 69620105ca1STaeung Song if (!section) { 69720105ca1STaeung Song section = add_section(sections, section_name); 69820105ca1STaeung Song if (!section) 69920105ca1STaeung Song goto out_free; 70020105ca1STaeung Song } 70120105ca1STaeung Song 70220105ca1STaeung Song item = find_config_item(name, section); 70320105ca1STaeung Song if (!item) { 70420105ca1STaeung Song item = add_config_item(section, name); 70520105ca1STaeung Song if (!item) 70620105ca1STaeung Song goto out_free; 70720105ca1STaeung Song } 70820105ca1STaeung Song 70908d090cfSTaeung Song /* perf_config_set can contain both user and system config items. 71008d090cfSTaeung Song * So we should know where each value is from. 71108d090cfSTaeung Song * The classification would be needed when a particular config file 7124d39c89fSIngo Molnar * is overwritten by setting feature i.e. set_config(). 71308d090cfSTaeung Song */ 71408d090cfSTaeung Song if (strcmp(config_file_name, perf_etc_perfconfig()) == 0) { 71508d090cfSTaeung Song section->from_system_config = true; 71608d090cfSTaeung Song item->from_system_config = true; 71708d090cfSTaeung Song } else { 71808d090cfSTaeung Song section->from_system_config = false; 71908d090cfSTaeung Song item->from_system_config = false; 72008d090cfSTaeung Song } 72108d090cfSTaeung Song 72220105ca1STaeung Song ret = set_value(item, value); 72320105ca1STaeung Song 72420105ca1STaeung Song out_free: 72520105ca1STaeung Song free(key); 72654569ba4SChangbin Du return ret; 72720105ca1STaeung Song } 72820105ca1STaeung Song 72908d090cfSTaeung Song int perf_config_set__collect(struct perf_config_set *set, const char *file_name, 730c6fc018aSTaeung Song const char *var, const char *value) 731c6fc018aSTaeung Song { 73208d090cfSTaeung Song config_file_name = file_name; 733c6fc018aSTaeung Song return collect_config(var, value, set); 734c6fc018aSTaeung Song } 735c6fc018aSTaeung Song 7368beeb00fSTaeung Song static int perf_config_set__init(struct perf_config_set *set) 7378beeb00fSTaeung Song { 7388beeb00fSTaeung Song int ret = -1; 7398beeb00fSTaeung Song 7408beeb00fSTaeung Song /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 7418beeb00fSTaeung Song if (config_exclusive_filename) 7428beeb00fSTaeung Song return perf_config_from_file(collect_config, config_exclusive_filename, set); 7438beeb00fSTaeung Song if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { 7448beeb00fSTaeung Song if (perf_config_from_file(collect_config, perf_etc_perfconfig(), set) < 0) 7458beeb00fSTaeung Song goto out; 7468beeb00fSTaeung Song } 747f5f03e19SJiri Olsa if (perf_config_global() && perf_home_perfconfig()) { 748f5f03e19SJiri Olsa if (perf_config_from_file(collect_config, perf_home_perfconfig(), set) < 0) 7498beeb00fSTaeung Song goto out; 7508beeb00fSTaeung Song } 7518beeb00fSTaeung Song 7528beeb00fSTaeung Song out: 7538beeb00fSTaeung Song return ret; 7548beeb00fSTaeung Song } 7558beeb00fSTaeung Song 75620105ca1STaeung Song struct perf_config_set *perf_config_set__new(void) 75720105ca1STaeung Song { 75820105ca1STaeung Song struct perf_config_set *set = zalloc(sizeof(*set)); 75920105ca1STaeung Song 76020105ca1STaeung Song if (set) { 76120105ca1STaeung Song INIT_LIST_HEAD(&set->sections); 76255421b4fSTaeung Song perf_config_set__init(set); 76320105ca1STaeung Song } 76420105ca1STaeung Song 76520105ca1STaeung Song return set; 76620105ca1STaeung Song } 76720105ca1STaeung Song 768a523026cSJiri Olsa struct perf_config_set *perf_config_set__load_file(const char *file) 769a523026cSJiri Olsa { 770a523026cSJiri Olsa struct perf_config_set *set = zalloc(sizeof(*set)); 771a523026cSJiri Olsa 772a523026cSJiri Olsa if (set) { 773a523026cSJiri Olsa INIT_LIST_HEAD(&set->sections); 774a523026cSJiri Olsa perf_config_from_file(collect_config, file, set); 775a523026cSJiri Olsa } 776a523026cSJiri Olsa 777a523026cSJiri Olsa return set; 778a523026cSJiri Olsa } 779a523026cSJiri Olsa 780d01bd1acSArnaldo Carvalho de Melo static int perf_config__init(void) 781d01bd1acSArnaldo Carvalho de Melo { 782d01bd1acSArnaldo Carvalho de Melo if (config_set == NULL) 783d01bd1acSArnaldo Carvalho de Melo config_set = perf_config_set__new(); 784d01bd1acSArnaldo Carvalho de Melo 785d01bd1acSArnaldo Carvalho de Melo return config_set == NULL; 786d01bd1acSArnaldo Carvalho de Melo } 787d01bd1acSArnaldo Carvalho de Melo 788a523026cSJiri Olsa int perf_config_set(struct perf_config_set *set, 789a523026cSJiri Olsa config_fn_t fn, void *data) 7908a0a9c7eSTaeung Song { 7918a0a9c7eSTaeung Song int ret = 0; 7928a0a9c7eSTaeung Song char key[BUFSIZ]; 7938a0a9c7eSTaeung Song struct perf_config_section *section; 7948a0a9c7eSTaeung Song struct perf_config_item *item; 7958a0a9c7eSTaeung Song 796a523026cSJiri Olsa perf_config_set__for_each_entry(set, section, item) { 7978a0a9c7eSTaeung Song char *value = item->value; 7988a0a9c7eSTaeung Song 7998a0a9c7eSTaeung Song if (value) { 8008a0a9c7eSTaeung Song scnprintf(key, sizeof(key), "%s.%s", 8018a0a9c7eSTaeung Song section->name, item->name); 8028a0a9c7eSTaeung Song ret = fn(key, value, data); 8038a0a9c7eSTaeung Song if (ret < 0) { 8048a0a9c7eSTaeung Song pr_err("Error: wrong config key-value pair %s=%s\n", 8058a0a9c7eSTaeung Song key, value); 80622d46219SArnaldo Carvalho de Melo /* 80722d46219SArnaldo Carvalho de Melo * Can't be just a 'break', as perf_config_set__for_each_entry() 80822d46219SArnaldo Carvalho de Melo * expands to two nested for() loops. 80922d46219SArnaldo Carvalho de Melo */ 81022d46219SArnaldo Carvalho de Melo goto out; 8118a0a9c7eSTaeung Song } 8128a0a9c7eSTaeung Song } 8138a0a9c7eSTaeung Song } 81422d46219SArnaldo Carvalho de Melo out: 8158a0a9c7eSTaeung Song return ret; 8168a0a9c7eSTaeung Song } 8178a0a9c7eSTaeung Song 818a523026cSJiri Olsa int perf_config(config_fn_t fn, void *data) 819a523026cSJiri Olsa { 820a523026cSJiri Olsa if (config_set == NULL && perf_config__init()) 821a523026cSJiri Olsa return -1; 822a523026cSJiri Olsa 823a523026cSJiri Olsa return perf_config_set(config_set, fn, data); 824a523026cSJiri Olsa } 825a523026cSJiri Olsa 8268a0a9c7eSTaeung Song void perf_config__exit(void) 8278a0a9c7eSTaeung Song { 8288a0a9c7eSTaeung Song perf_config_set__delete(config_set); 8298a0a9c7eSTaeung Song config_set = NULL; 8308a0a9c7eSTaeung Song } 8318a0a9c7eSTaeung Song 8328a0a9c7eSTaeung Song void perf_config__refresh(void) 8338a0a9c7eSTaeung Song { 8348a0a9c7eSTaeung Song perf_config__exit(); 8358a0a9c7eSTaeung Song perf_config__init(); 8368a0a9c7eSTaeung Song } 8378a0a9c7eSTaeung Song 83820105ca1STaeung Song static void perf_config_item__delete(struct perf_config_item *item) 83920105ca1STaeung Song { 84020105ca1STaeung Song zfree(&item->name); 84120105ca1STaeung Song zfree(&item->value); 84220105ca1STaeung Song free(item); 84320105ca1STaeung Song } 84420105ca1STaeung Song 84520105ca1STaeung Song static void perf_config_section__purge(struct perf_config_section *section) 84620105ca1STaeung Song { 84720105ca1STaeung Song struct perf_config_item *item, *tmp; 84820105ca1STaeung Song 84920105ca1STaeung Song list_for_each_entry_safe(item, tmp, §ion->items, node) { 85020105ca1STaeung Song list_del_init(&item->node); 85120105ca1STaeung Song perf_config_item__delete(item); 85220105ca1STaeung Song } 85320105ca1STaeung Song } 85420105ca1STaeung Song 85520105ca1STaeung Song static void perf_config_section__delete(struct perf_config_section *section) 85620105ca1STaeung Song { 85720105ca1STaeung Song perf_config_section__purge(section); 85820105ca1STaeung Song zfree(§ion->name); 85920105ca1STaeung Song free(section); 86020105ca1STaeung Song } 86120105ca1STaeung Song 86220105ca1STaeung Song static void perf_config_set__purge(struct perf_config_set *set) 86320105ca1STaeung Song { 86420105ca1STaeung Song struct perf_config_section *section, *tmp; 86520105ca1STaeung Song 86620105ca1STaeung Song list_for_each_entry_safe(section, tmp, &set->sections, node) { 86720105ca1STaeung Song list_del_init(§ion->node); 86820105ca1STaeung Song perf_config_section__delete(section); 86920105ca1STaeung Song } 87020105ca1STaeung Song } 87120105ca1STaeung Song 87220105ca1STaeung Song void perf_config_set__delete(struct perf_config_set *set) 87320105ca1STaeung Song { 874826424ccSTaeung Song if (set == NULL) 875826424ccSTaeung Song return; 876826424ccSTaeung Song 87720105ca1STaeung Song perf_config_set__purge(set); 87820105ca1STaeung Song free(set); 87920105ca1STaeung Song } 88020105ca1STaeung Song 88186470930SIngo Molnar /* 88286470930SIngo Molnar * Call this to report error for your variable that should not 88386470930SIngo Molnar * get a boolean value (i.e. "[my] var" means "true"). 88486470930SIngo Molnar */ 88586470930SIngo Molnar int config_error_nonbool(const char *var) 88686470930SIngo Molnar { 88762d94b00SArnaldo Carvalho de Melo pr_err("Missing value for '%s'", var); 88862d94b00SArnaldo Carvalho de Melo return -1; 88986470930SIngo Molnar } 89045de34bbSStephane Eranian 89199ce8e9fSJiri Olsa void set_buildid_dir(const char *dir) 89245de34bbSStephane Eranian { 89399ce8e9fSJiri Olsa if (dir) 89475c375c0SSihyeon Jang scnprintf(buildid_dir, MAXPATHLEN, "%s", dir); 89545de34bbSStephane Eranian 89645de34bbSStephane Eranian /* default to $HOME/.debug */ 89745de34bbSStephane Eranian if (buildid_dir[0] == '\0') { 89837194f44STaeung Song char *home = getenv("HOME"); 89937194f44STaeung Song 90037194f44STaeung Song if (home) { 90175c375c0SSihyeon Jang snprintf(buildid_dir, MAXPATHLEN, "%s/%s", 90237194f44STaeung Song home, DEBUG_CACHE_DIR); 90345de34bbSStephane Eranian } else { 90445de34bbSStephane Eranian strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1); 90545de34bbSStephane Eranian } 90645de34bbSStephane Eranian buildid_dir[MAXPATHLEN-1] = '\0'; 90745de34bbSStephane Eranian } 90845de34bbSStephane Eranian /* for communicating with external commands */ 90945de34bbSStephane Eranian setenv("PERF_BUILDID_DIR", buildid_dir, 1); 91045de34bbSStephane Eranian } 911