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 return intel_pt_pmu_default_config(pmu); 32 if (!strcmp(pmu->name, INTEL_BTS_PMU_NAME)) 33 pmu->selectable = true; 34 #endif 35 return NULL; 36 } 37 38 static void pmu_alias__delete(struct pmu_alias *pmu_alias) 39 { 40 if (!pmu_alias) 41 return; 42 43 zfree(&pmu_alias->name); 44 zfree(&pmu_alias->alias); 45 free(pmu_alias); 46 } 47 48 static struct pmu_alias *pmu_alias__new(char *name, char *alias) 49 { 50 struct pmu_alias *pmu_alias = zalloc(sizeof(*pmu_alias)); 51 52 if (pmu_alias) { 53 pmu_alias->name = strdup(name); 54 if (!pmu_alias->name) 55 goto out_delete; 56 57 pmu_alias->alias = strdup(alias); 58 if (!pmu_alias->alias) 59 goto out_delete; 60 } 61 return pmu_alias; 62 63 out_delete: 64 pmu_alias__delete(pmu_alias); 65 return NULL; 66 } 67 68 static int setup_pmu_alias_list(void) 69 { 70 char path[PATH_MAX]; 71 DIR *dir; 72 struct dirent *dent; 73 struct pmu_alias *pmu_alias; 74 char buf[MAX_PMU_NAME_LEN]; 75 FILE *file; 76 int ret = -ENOMEM; 77 78 if (!perf_pmu__event_source_devices_scnprintf(path, sizeof(path))) 79 return -1; 80 81 dir = opendir(path); 82 if (!dir) 83 return -errno; 84 85 while ((dent = readdir(dir))) { 86 if (!strcmp(dent->d_name, ".") || 87 !strcmp(dent->d_name, "..")) 88 continue; 89 90 perf_pmu__pathname_scnprintf(path, sizeof(path), dent->d_name, "alias"); 91 if (!file_available(path)) 92 continue; 93 94 file = fopen(path, "r"); 95 if (!file) 96 continue; 97 98 if (!fgets(buf, sizeof(buf), file)) { 99 fclose(file); 100 continue; 101 } 102 103 fclose(file); 104 105 /* Remove the last '\n' */ 106 buf[strlen(buf) - 1] = 0; 107 108 pmu_alias = pmu_alias__new(dent->d_name, buf); 109 if (!pmu_alias) 110 goto close_dir; 111 112 list_add_tail(&pmu_alias->list, &pmu_alias_name_list); 113 } 114 115 ret = 0; 116 117 close_dir: 118 closedir(dir); 119 return ret; 120 } 121 122 static char *__pmu_find_real_name(const char *name) 123 { 124 struct pmu_alias *pmu_alias; 125 126 list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { 127 if (!strcmp(name, pmu_alias->alias)) 128 return pmu_alias->name; 129 } 130 131 return (char *)name; 132 } 133 134 char *pmu_find_real_name(const char *name) 135 { 136 if (cached_list) 137 return __pmu_find_real_name(name); 138 139 setup_pmu_alias_list(); 140 cached_list = true; 141 142 return __pmu_find_real_name(name); 143 } 144 145 static char *__pmu_find_alias_name(const char *name) 146 { 147 struct pmu_alias *pmu_alias; 148 149 list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { 150 if (!strcmp(name, pmu_alias->name)) 151 return pmu_alias->alias; 152 } 153 return NULL; 154 } 155 156 char *pmu_find_alias_name(const char *name) 157 { 158 if (cached_list) 159 return __pmu_find_alias_name(name); 160 161 setup_pmu_alias_list(); 162 cached_list = true; 163 164 return __pmu_find_alias_name(name); 165 } 166