cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pmu.c (3324B)


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