1 // SPDX-License-Identifier: GPL-2.0 2 #include <string.h> 3 #include <stdio.h> 4 #include <sys/types.h> 5 #include <dirent.h> 6 #include <fcntl.h> 7 #include <linux/stddef.h> 8 #include <linux/perf_event.h> 9 #include <linux/zalloc.h> 10 #include <api/fs/fs.h> 11 #include <errno.h> 12 13 #include "../../../util/intel-pt.h" 14 #include "../../../util/intel-bts.h" 15 #include "../../../util/pmu.h" 16 #include "../../../util/fncache.h" 17 18 struct pmu_alias { 19 char *name; 20 char *alias; 21 struct list_head list; 22 }; 23 24 static LIST_HEAD(pmu_alias_name_list); 25 static bool cached_list; 26 27 struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 28 { 29 #ifdef HAVE_AUXTRACE_SUPPORT 30 if (!strcmp(pmu->name, INTEL_PT_PMU_NAME)) { 31 pmu->auxtrace = true; 32 return intel_pt_pmu_default_config(pmu); 33 } 34 if (!strcmp(pmu->name, INTEL_BTS_PMU_NAME)) { 35 pmu->auxtrace = true; 36 pmu->selectable = true; 37 } 38 #endif 39 return NULL; 40 } 41 42 static void pmu_alias__delete(struct pmu_alias *pmu_alias) 43 { 44 if (!pmu_alias) 45 return; 46 47 zfree(&pmu_alias->name); 48 zfree(&pmu_alias->alias); 49 free(pmu_alias); 50 } 51 52 static struct pmu_alias *pmu_alias__new(char *name, char *alias) 53 { 54 struct pmu_alias *pmu_alias = zalloc(sizeof(*pmu_alias)); 55 56 if (pmu_alias) { 57 pmu_alias->name = strdup(name); 58 if (!pmu_alias->name) 59 goto out_delete; 60 61 pmu_alias->alias = strdup(alias); 62 if (!pmu_alias->alias) 63 goto out_delete; 64 } 65 return pmu_alias; 66 67 out_delete: 68 pmu_alias__delete(pmu_alias); 69 return NULL; 70 } 71 72 static int setup_pmu_alias_list(void) 73 { 74 int fd, dirfd; 75 DIR *dir; 76 struct dirent *dent; 77 struct pmu_alias *pmu_alias; 78 char buf[MAX_PMU_NAME_LEN]; 79 FILE *file; 80 int ret = -ENOMEM; 81 82 dirfd = perf_pmu__event_source_devices_fd(); 83 if (dirfd < 0) 84 return -1; 85 86 dir = fdopendir(dirfd); 87 if (!dir) 88 return -errno; 89 90 while ((dent = readdir(dir))) { 91 if (!strcmp(dent->d_name, ".") || 92 !strcmp(dent->d_name, "..")) 93 continue; 94 95 fd = perf_pmu__pathname_fd(dirfd, dent->d_name, "alias", O_RDONLY); 96 if (fd < 0) 97 continue; 98 99 file = fdopen(fd, "r"); 100 if (!file) 101 continue; 102 103 if (!fgets(buf, sizeof(buf), file)) { 104 fclose(file); 105 continue; 106 } 107 108 fclose(file); 109 110 /* Remove the last '\n' */ 111 buf[strlen(buf) - 1] = 0; 112 113 pmu_alias = pmu_alias__new(dent->d_name, buf); 114 if (!pmu_alias) 115 goto close_dir; 116 117 list_add_tail(&pmu_alias->list, &pmu_alias_name_list); 118 } 119 120 ret = 0; 121 122 close_dir: 123 closedir(dir); 124 return ret; 125 } 126 127 static char *__pmu_find_real_name(const char *name) 128 { 129 struct pmu_alias *pmu_alias; 130 131 list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { 132 if (!strcmp(name, pmu_alias->alias)) 133 return pmu_alias->name; 134 } 135 136 return (char *)name; 137 } 138 139 char *pmu_find_real_name(const char *name) 140 { 141 if (cached_list) 142 return __pmu_find_real_name(name); 143 144 setup_pmu_alias_list(); 145 cached_list = true; 146 147 return __pmu_find_real_name(name); 148 } 149 150 static char *__pmu_find_alias_name(const char *name) 151 { 152 struct pmu_alias *pmu_alias; 153 154 list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { 155 if (!strcmp(name, pmu_alias->name)) 156 return pmu_alias->alias; 157 } 158 return NULL; 159 } 160 161 char *pmu_find_alias_name(const char *name) 162 { 163 if (cached_list) 164 return __pmu_find_alias_name(name); 165 166 setup_pmu_alias_list(); 167 cached_list = true; 168 169 return __pmu_find_alias_name(name); 170 } 171