// SPDX-License-Identifier: GPL-2.0 #include #include #include #include #include #include #include #include #include #include #include "../../../util/intel-pt.h" #include "../../../util/intel-bts.h" #include "../../../util/pmu.h" #include "../../../util/fncache.h" #define TEMPLATE_ALIAS "%s/bus/event_source/devices/%s/alias" struct pmu_alias { char *name; char *alias; struct list_head list; }; static LIST_HEAD(pmu_alias_name_list); static bool cached_list; struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) { #ifdef HAVE_AUXTRACE_SUPPORT if (!strcmp(pmu->name, INTEL_PT_PMU_NAME)) return intel_pt_pmu_default_config(pmu); if (!strcmp(pmu->name, INTEL_BTS_PMU_NAME)) pmu->selectable = true; #endif return NULL; } static void pmu_alias__delete(struct pmu_alias *pmu_alias) { if (!pmu_alias) return; zfree(&pmu_alias->name); zfree(&pmu_alias->alias); free(pmu_alias); } static struct pmu_alias *pmu_alias__new(char *name, char *alias) { struct pmu_alias *pmu_alias = zalloc(sizeof(*pmu_alias)); if (pmu_alias) { pmu_alias->name = strdup(name); if (!pmu_alias->name) goto out_delete; pmu_alias->alias = strdup(alias); if (!pmu_alias->alias) goto out_delete; } return pmu_alias; out_delete: pmu_alias__delete(pmu_alias); return NULL; } static int setup_pmu_alias_list(void) { char path[PATH_MAX]; DIR *dir; struct dirent *dent; const char *sysfs = sysfs__mountpoint(); struct pmu_alias *pmu_alias; char buf[MAX_PMU_NAME_LEN]; FILE *file; int ret = -ENOMEM; if (!sysfs) return -1; snprintf(path, PATH_MAX, "%s" EVENT_SOURCE_DEVICE_PATH, sysfs); dir = opendir(path); if (!dir) return -errno; while ((dent = readdir(dir))) { if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue; snprintf(path, PATH_MAX, TEMPLATE_ALIAS, sysfs, dent->d_name); if (!file_available(path)) continue; file = fopen(path, "r"); if (!file) continue; if (!fgets(buf, sizeof(buf), file)) { fclose(file); continue; } fclose(file); /* Remove the last '\n' */ buf[strlen(buf) - 1] = 0; pmu_alias = pmu_alias__new(dent->d_name, buf); if (!pmu_alias) goto close_dir; list_add_tail(&pmu_alias->list, &pmu_alias_name_list); } ret = 0; close_dir: closedir(dir); return ret; } static char *__pmu_find_real_name(const char *name) { struct pmu_alias *pmu_alias; list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { if (!strcmp(name, pmu_alias->alias)) return pmu_alias->name; } return (char *)name; } char *pmu_find_real_name(const char *name) { if (cached_list) return __pmu_find_real_name(name); setup_pmu_alias_list(); cached_list = true; return __pmu_find_real_name(name); } static char *__pmu_find_alias_name(const char *name) { struct pmu_alias *pmu_alias; list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { if (!strcmp(name, pmu_alias->name)) return pmu_alias->alias; } return NULL; } char *pmu_find_alias_name(const char *name) { if (cached_list) return __pmu_find_alias_name(name); setup_pmu_alias_list(); cached_list = true; return __pmu_find_alias_name(name); }