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
perf_pmu__get_default_config(struct perf_pmu * pmu __maybe_unused)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
pmu_alias__delete(struct pmu_alias * pmu_alias)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
pmu_alias__new(char * name,char * alias)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
setup_pmu_alias_list(void)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
__pmu_find_real_name(const char * name)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
pmu_find_real_name(const char * name)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
__pmu_find_alias_name(const char * name)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
pmu_find_alias_name(const char * name)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