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 char path[PATH_MAX]; 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 if (!perf_pmu__event_source_devices_scnprintf(path, sizeof(path))) 83 return -1; 84 85 dir = opendir(path); 86 if (!dir) 87 return -errno; 88 89 while ((dent = readdir(dir))) { 90 if (!strcmp(dent->d_name, ".") || 91 !strcmp(dent->d_name, "..")) 92 continue; 93 94 perf_pmu__pathname_scnprintf(path, sizeof(path), dent->d_name, "alias"); 95 if (!file_available(path)) 96 continue; 97 98 file = fopen(path, "r"); 99 if (!file) 100 continue; 101 102 if (!fgets(buf, sizeof(buf), file)) { 103 fclose(file); 104 continue; 105 } 106 107 fclose(file); 108 109 /* Remove the last '\n' */ 110 buf[strlen(buf) - 1] = 0; 111 112 pmu_alias = pmu_alias__new(dent->d_name, buf); 113 if (!pmu_alias) 114 goto close_dir; 115 116 list_add_tail(&pmu_alias->list, &pmu_alias_name_list); 117 } 118 119 ret = 0; 120 121 close_dir: 122 closedir(dir); 123 return ret; 124 } 125 126 static char *__pmu_find_real_name(const char *name) 127 { 128 struct pmu_alias *pmu_alias; 129 130 list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { 131 if (!strcmp(name, pmu_alias->alias)) 132 return pmu_alias->name; 133 } 134 135 return (char *)name; 136 } 137 138 char *pmu_find_real_name(const char *name) 139 { 140 if (cached_list) 141 return __pmu_find_real_name(name); 142 143 setup_pmu_alias_list(); 144 cached_list = true; 145 146 return __pmu_find_real_name(name); 147 } 148 149 static char *__pmu_find_alias_name(const char *name) 150 { 151 struct pmu_alias *pmu_alias; 152 153 list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { 154 if (!strcmp(name, pmu_alias->name)) 155 return pmu_alias->alias; 156 } 157 return NULL; 158 } 159 160 char *pmu_find_alias_name(const char *name) 161 { 162 if (cached_list) 163 return __pmu_find_alias_name(name); 164 165 setup_pmu_alias_list(); 166 cached_list = true; 167 168 return __pmu_find_alias_name(name); 169 } 170