0001
0002 #include <string.h>
0003 #include <stdio.h>
0004 #include <sys/types.h>
0005 #include <dirent.h>
0006 #include <fcntl.h>
0007 #include <linux/stddef.h>
0008 #include <linux/perf_event.h>
0009 #include <linux/zalloc.h>
0010 #include <api/fs/fs.h>
0011 #include <errno.h>
0012
0013 #include "../../../util/intel-pt.h"
0014 #include "../../../util/intel-bts.h"
0015 #include "../../../util/pmu.h"
0016 #include "../../../util/fncache.h"
0017
0018 #define TEMPLATE_ALIAS "%s/bus/event_source/devices/%s/alias"
0019
0020 struct pmu_alias {
0021 char *name;
0022 char *alias;
0023 struct list_head list;
0024 };
0025
0026 static LIST_HEAD(pmu_alias_name_list);
0027 static bool cached_list;
0028
0029 struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
0030 {
0031 #ifdef HAVE_AUXTRACE_SUPPORT
0032 if (!strcmp(pmu->name, INTEL_PT_PMU_NAME))
0033 return intel_pt_pmu_default_config(pmu);
0034 if (!strcmp(pmu->name, INTEL_BTS_PMU_NAME))
0035 pmu->selectable = true;
0036 #endif
0037 return NULL;
0038 }
0039
0040 static void pmu_alias__delete(struct pmu_alias *pmu_alias)
0041 {
0042 if (!pmu_alias)
0043 return;
0044
0045 zfree(&pmu_alias->name);
0046 zfree(&pmu_alias->alias);
0047 free(pmu_alias);
0048 }
0049
0050 static struct pmu_alias *pmu_alias__new(char *name, char *alias)
0051 {
0052 struct pmu_alias *pmu_alias = zalloc(sizeof(*pmu_alias));
0053
0054 if (pmu_alias) {
0055 pmu_alias->name = strdup(name);
0056 if (!pmu_alias->name)
0057 goto out_delete;
0058
0059 pmu_alias->alias = strdup(alias);
0060 if (!pmu_alias->alias)
0061 goto out_delete;
0062 }
0063 return pmu_alias;
0064
0065 out_delete:
0066 pmu_alias__delete(pmu_alias);
0067 return NULL;
0068 }
0069
0070 static int setup_pmu_alias_list(void)
0071 {
0072 char path[PATH_MAX];
0073 DIR *dir;
0074 struct dirent *dent;
0075 const char *sysfs = sysfs__mountpoint();
0076 struct pmu_alias *pmu_alias;
0077 char buf[MAX_PMU_NAME_LEN];
0078 FILE *file;
0079 int ret = -ENOMEM;
0080
0081 if (!sysfs)
0082 return -1;
0083
0084 snprintf(path, PATH_MAX,
0085 "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
0086
0087 dir = opendir(path);
0088 if (!dir)
0089 return -errno;
0090
0091 while ((dent = readdir(dir))) {
0092 if (!strcmp(dent->d_name, ".") ||
0093 !strcmp(dent->d_name, ".."))
0094 continue;
0095
0096 snprintf(path, PATH_MAX,
0097 TEMPLATE_ALIAS, sysfs, dent->d_name);
0098
0099 if (!file_available(path))
0100 continue;
0101
0102 file = fopen(path, "r");
0103 if (!file)
0104 continue;
0105
0106 if (!fgets(buf, sizeof(buf), file)) {
0107 fclose(file);
0108 continue;
0109 }
0110
0111 fclose(file);
0112
0113
0114 buf[strlen(buf) - 1] = 0;
0115
0116 pmu_alias = pmu_alias__new(dent->d_name, buf);
0117 if (!pmu_alias)
0118 goto close_dir;
0119
0120 list_add_tail(&pmu_alias->list, &pmu_alias_name_list);
0121 }
0122
0123 ret = 0;
0124
0125 close_dir:
0126 closedir(dir);
0127 return ret;
0128 }
0129
0130 static char *__pmu_find_real_name(const char *name)
0131 {
0132 struct pmu_alias *pmu_alias;
0133
0134 list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) {
0135 if (!strcmp(name, pmu_alias->alias))
0136 return pmu_alias->name;
0137 }
0138
0139 return (char *)name;
0140 }
0141
0142 char *pmu_find_real_name(const char *name)
0143 {
0144 if (cached_list)
0145 return __pmu_find_real_name(name);
0146
0147 setup_pmu_alias_list();
0148 cached_list = true;
0149
0150 return __pmu_find_real_name(name);
0151 }
0152
0153 static char *__pmu_find_alias_name(const char *name)
0154 {
0155 struct pmu_alias *pmu_alias;
0156
0157 list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) {
0158 if (!strcmp(name, pmu_alias->name))
0159 return pmu_alias->alias;
0160 }
0161 return NULL;
0162 }
0163
0164 char *pmu_find_alias_name(const char *name)
0165 {
0166 if (cached_list)
0167 return __pmu_find_alias_name(name);
0168
0169 setup_pmu_alias_list();
0170 cached_list = true;
0171
0172 return __pmu_find_alias_name(name);
0173 }