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

event-plugin.c (15518B)


      1// SPDX-License-Identifier: LGPL-2.1
      2/*
      3 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
      4 *
      5 */
      6
      7#include <ctype.h>
      8#include <stdio.h>
      9#include <string.h>
     10#include <dlfcn.h>
     11#include <stdlib.h>
     12#include <sys/types.h>
     13#include <sys/stat.h>
     14#include <unistd.h>
     15#include <dirent.h>
     16#include <errno.h>
     17#include "event-parse.h"
     18#include "event-parse-local.h"
     19#include "event-utils.h"
     20#include "trace-seq.h"
     21
     22#define LOCAL_PLUGIN_DIR ".local/lib/traceevent/plugins/"
     23
     24static struct registered_plugin_options {
     25	struct registered_plugin_options	*next;
     26	struct tep_plugin_option		*options;
     27} *registered_options;
     28
     29static struct trace_plugin_options {
     30	struct trace_plugin_options	*next;
     31	char				*plugin;
     32	char				*option;
     33	char				*value;
     34} *trace_plugin_options;
     35
     36struct tep_plugin_list {
     37	struct tep_plugin_list	*next;
     38	char			*name;
     39	void			*handle;
     40};
     41
     42struct tep_plugins_dir {
     43	struct tep_plugins_dir		*next;
     44	char				*path;
     45	enum tep_plugin_load_priority	prio;
     46};
     47
     48static void lower_case(char *str)
     49{
     50	if (!str)
     51		return;
     52	for (; *str; str++)
     53		*str = tolower(*str);
     54}
     55
     56static int update_option_value(struct tep_plugin_option *op, const char *val)
     57{
     58	char *op_val;
     59
     60	if (!val) {
     61		/* toggle, only if option is boolean */
     62		if (op->value)
     63			/* Warn? */
     64			return 0;
     65		op->set ^= 1;
     66		return 0;
     67	}
     68
     69	/*
     70	 * If the option has a value then it takes a string
     71	 * otherwise the option is a boolean.
     72	 */
     73	if (op->value) {
     74		op->value = val;
     75		return 0;
     76	}
     77
     78	/* Option is boolean, must be either "1", "0", "true" or "false" */
     79
     80	op_val = strdup(val);
     81	if (!op_val)
     82		return -1;
     83	lower_case(op_val);
     84
     85	if (strcmp(val, "1") == 0 || strcmp(val, "true") == 0)
     86		op->set = 1;
     87	else if (strcmp(val, "0") == 0 || strcmp(val, "false") == 0)
     88		op->set = 0;
     89	free(op_val);
     90
     91	return 0;
     92}
     93
     94/**
     95 * tep_plugin_list_options - get list of plugin options
     96 *
     97 * Returns an array of char strings that list the currently registered
     98 * plugin options in the format of <plugin>:<option>. This list can be
     99 * used by toggling the option.
    100 *
    101 * Returns NULL if there's no options registered. On error it returns
    102 * INVALID_PLUGIN_LIST_OPTION
    103 *
    104 * Must be freed with tep_plugin_free_options_list().
    105 */
    106char **tep_plugin_list_options(void)
    107{
    108	struct registered_plugin_options *reg;
    109	struct tep_plugin_option *op;
    110	char **list = NULL;
    111	char *name;
    112	int count = 0;
    113
    114	for (reg = registered_options; reg; reg = reg->next) {
    115		for (op = reg->options; op->name; op++) {
    116			char *alias = op->plugin_alias ? op->plugin_alias : op->file;
    117			char **temp = list;
    118			int ret;
    119
    120			ret = asprintf(&name, "%s:%s", alias, op->name);
    121			if (ret < 0)
    122				goto err;
    123
    124			list = realloc(list, count + 2);
    125			if (!list) {
    126				list = temp;
    127				free(name);
    128				goto err;
    129			}
    130			list[count++] = name;
    131			list[count] = NULL;
    132		}
    133	}
    134	return list;
    135
    136 err:
    137	while (--count >= 0)
    138		free(list[count]);
    139	free(list);
    140
    141	return INVALID_PLUGIN_LIST_OPTION;
    142}
    143
    144void tep_plugin_free_options_list(char **list)
    145{
    146	int i;
    147
    148	if (!list)
    149		return;
    150
    151	if (list == INVALID_PLUGIN_LIST_OPTION)
    152		return;
    153
    154	for (i = 0; list[i]; i++)
    155		free(list[i]);
    156
    157	free(list);
    158}
    159
    160static int
    161update_option(const char *file, struct tep_plugin_option *option)
    162{
    163	struct trace_plugin_options *op;
    164	char *plugin;
    165	int ret = 0;
    166
    167	if (option->plugin_alias) {
    168		plugin = strdup(option->plugin_alias);
    169		if (!plugin)
    170			return -1;
    171	} else {
    172		char *p;
    173		plugin = strdup(file);
    174		if (!plugin)
    175			return -1;
    176		p = strstr(plugin, ".");
    177		if (p)
    178			*p = '\0';
    179	}
    180
    181	/* first look for named options */
    182	for (op = trace_plugin_options; op; op = op->next) {
    183		if (!op->plugin)
    184			continue;
    185		if (strcmp(op->plugin, plugin) != 0)
    186			continue;
    187		if (strcmp(op->option, option->name) != 0)
    188			continue;
    189
    190		ret = update_option_value(option, op->value);
    191		if (ret)
    192			goto out;
    193		break;
    194	}
    195
    196	/* first look for unnamed options */
    197	for (op = trace_plugin_options; op; op = op->next) {
    198		if (op->plugin)
    199			continue;
    200		if (strcmp(op->option, option->name) != 0)
    201			continue;
    202
    203		ret = update_option_value(option, op->value);
    204		break;
    205	}
    206
    207 out:
    208	free(plugin);
    209	return ret;
    210}
    211
    212/**
    213 * tep_plugin_add_options - Add a set of options by a plugin
    214 * @name: The name of the plugin adding the options
    215 * @options: The set of options being loaded
    216 *
    217 * Sets the options with the values that have been added by user.
    218 */
    219int tep_plugin_add_options(const char *name,
    220			   struct tep_plugin_option *options)
    221{
    222	struct registered_plugin_options *reg;
    223
    224	reg = malloc(sizeof(*reg));
    225	if (!reg)
    226		return -1;
    227	reg->next = registered_options;
    228	reg->options = options;
    229	registered_options = reg;
    230
    231	while (options->name) {
    232		update_option(name, options);
    233		options++;
    234	}
    235	return 0;
    236}
    237
    238/**
    239 * tep_plugin_remove_options - remove plugin options that were registered
    240 * @options: Options to removed that were registered with tep_plugin_add_options
    241 */
    242void tep_plugin_remove_options(struct tep_plugin_option *options)
    243{
    244	struct registered_plugin_options **last;
    245	struct registered_plugin_options *reg;
    246
    247	for (last = &registered_options; *last; last = &(*last)->next) {
    248		if ((*last)->options == options) {
    249			reg = *last;
    250			*last = reg->next;
    251			free(reg);
    252			return;
    253		}
    254	}
    255}
    256
    257static int parse_option_name(char **option, char **plugin)
    258{
    259	char *p;
    260
    261	*plugin = NULL;
    262
    263	if ((p = strstr(*option, ":"))) {
    264		*plugin = *option;
    265		*p = '\0';
    266		*option = strdup(p + 1);
    267		if (!*option)
    268			return -1;
    269	}
    270	return 0;
    271}
    272
    273static struct tep_plugin_option *
    274find_registered_option(const char *plugin, const char *option)
    275{
    276	struct registered_plugin_options *reg;
    277	struct tep_plugin_option *op;
    278	const char *op_plugin;
    279
    280	for (reg = registered_options; reg; reg = reg->next) {
    281		for (op = reg->options; op->name; op++) {
    282			if (op->plugin_alias)
    283				op_plugin = op->plugin_alias;
    284			else
    285				op_plugin = op->file;
    286
    287			if (plugin && strcmp(plugin, op_plugin) != 0)
    288				continue;
    289			if (strcmp(option, op->name) != 0)
    290				continue;
    291
    292			return op;
    293		}
    294	}
    295
    296	return NULL;
    297}
    298
    299static int process_option(const char *plugin, const char *option, const char *val)
    300{
    301	struct tep_plugin_option *op;
    302
    303	op = find_registered_option(plugin, option);
    304	if (!op)
    305		return 0;
    306
    307	return update_option_value(op, val);
    308}
    309
    310/**
    311 * tep_plugin_add_option - add an option/val pair to set plugin options
    312 * @name: The name of the option (format: <plugin>:<option> or just <option>)
    313 * @val: (optional) the value for the option
    314 *
    315 * Modify a plugin option. If @val is given than the value of the option
    316 * is set (note, some options just take a boolean, so @val must be either
    317 * "1" or "0" or "true" or "false").
    318 */
    319int tep_plugin_add_option(const char *name, const char *val)
    320{
    321	struct trace_plugin_options *op;
    322	char *option_str;
    323	char *plugin;
    324
    325	option_str = strdup(name);
    326	if (!option_str)
    327		return -ENOMEM;
    328
    329	if (parse_option_name(&option_str, &plugin) < 0)
    330		return -ENOMEM;
    331
    332	/* If the option exists, update the val */
    333	for (op = trace_plugin_options; op; op = op->next) {
    334		/* Both must be NULL or not NULL */
    335		if ((!plugin || !op->plugin) && plugin != op->plugin)
    336			continue;
    337		if (plugin && strcmp(plugin, op->plugin) != 0)
    338			continue;
    339		if (strcmp(op->option, option_str) != 0)
    340			continue;
    341
    342		/* update option */
    343		free(op->value);
    344		if (val) {
    345			op->value = strdup(val);
    346			if (!op->value)
    347				goto out_free;
    348		} else
    349			op->value = NULL;
    350
    351		/* plugin and option_str don't get freed at the end */
    352		free(plugin);
    353		free(option_str);
    354
    355		plugin = op->plugin;
    356		option_str = op->option;
    357		break;
    358	}
    359
    360	/* If not found, create */
    361	if (!op) {
    362		op = malloc(sizeof(*op));
    363		if (!op)
    364			goto out_free;
    365		memset(op, 0, sizeof(*op));
    366		op->plugin = plugin;
    367		op->option = option_str;
    368		if (val) {
    369			op->value = strdup(val);
    370			if (!op->value) {
    371				free(op);
    372				goto out_free;
    373			}
    374		}
    375		op->next = trace_plugin_options;
    376		trace_plugin_options = op;
    377	}
    378
    379	return process_option(plugin, option_str, val);
    380
    381out_free:
    382	free(plugin);
    383	free(option_str);
    384	return -ENOMEM;
    385}
    386
    387static void print_op_data(struct trace_seq *s, const char *name,
    388			  const char *op)
    389{
    390	if (op)
    391		trace_seq_printf(s, "%8s:\t%s\n", name, op);
    392}
    393
    394/**
    395 * tep_plugin_print_options - print out the registered plugin options
    396 * @s: The trace_seq descriptor to write the plugin options into
    397 *
    398 * Writes a list of options into trace_seq @s.
    399 */
    400void tep_plugin_print_options(struct trace_seq *s)
    401{
    402	struct registered_plugin_options *reg;
    403	struct tep_plugin_option *op;
    404
    405	for (reg = registered_options; reg; reg = reg->next) {
    406		if (reg != registered_options)
    407			trace_seq_printf(s, "============\n");
    408		for (op = reg->options; op->name; op++) {
    409			if (op != reg->options)
    410				trace_seq_printf(s, "------------\n");
    411			print_op_data(s, "file", op->file);
    412			print_op_data(s, "plugin", op->plugin_alias);
    413			print_op_data(s, "option", op->name);
    414			print_op_data(s, "desc", op->description);
    415			print_op_data(s, "value", op->value);
    416			trace_seq_printf(s, "%8s:\t%d\n", "set", op->set);
    417		}
    418	}
    419}
    420
    421/**
    422 * tep_print_plugins - print out the list of plugins loaded
    423 * @s: the trace_seq descripter to write to
    424 * @prefix: The prefix string to add before listing the option name
    425 * @suffix: The suffix string ot append after the option name
    426 * @list: The list of plugins (usually returned by tep_load_plugins()
    427 *
    428 * Writes to the trace_seq @s the list of plugins (files) that is
    429 * returned by tep_load_plugins(). Use @prefix and @suffix for formating:
    430 * @prefix = "  ", @suffix = "\n".
    431 */
    432void tep_print_plugins(struct trace_seq *s,
    433		       const char *prefix, const char *suffix,
    434		       const struct tep_plugin_list *list)
    435{
    436	while (list) {
    437		trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
    438		list = list->next;
    439	}
    440}
    441
    442static void
    443load_plugin(struct tep_handle *tep, const char *path,
    444	    const char *file, void *data)
    445{
    446	struct tep_plugin_list **plugin_list = data;
    447	struct tep_plugin_option *options;
    448	tep_plugin_load_func func;
    449	struct tep_plugin_list *list;
    450	const char *alias;
    451	char *plugin;
    452	void *handle;
    453	int ret;
    454
    455	ret = asprintf(&plugin, "%s/%s", path, file);
    456	if (ret < 0) {
    457		warning("could not allocate plugin memory\n");
    458		return;
    459	}
    460
    461	handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
    462	if (!handle) {
    463		warning("could not load plugin '%s'\n%s\n",
    464			plugin, dlerror());
    465		goto out_free;
    466	}
    467
    468	alias = dlsym(handle, TEP_PLUGIN_ALIAS_NAME);
    469	if (!alias)
    470		alias = file;
    471
    472	options = dlsym(handle, TEP_PLUGIN_OPTIONS_NAME);
    473	if (options) {
    474		while (options->name) {
    475			ret = update_option(alias, options);
    476			if (ret < 0)
    477				goto out_free;
    478			options++;
    479		}
    480	}
    481
    482	func = dlsym(handle, TEP_PLUGIN_LOADER_NAME);
    483	if (!func) {
    484		warning("could not find func '%s' in plugin '%s'\n%s\n",
    485			TEP_PLUGIN_LOADER_NAME, plugin, dlerror());
    486		goto out_free;
    487	}
    488
    489	list = malloc(sizeof(*list));
    490	if (!list) {
    491		warning("could not allocate plugin memory\n");
    492		goto out_free;
    493	}
    494
    495	list->next = *plugin_list;
    496	list->handle = handle;
    497	list->name = plugin;
    498	*plugin_list = list;
    499
    500	pr_stat("registering plugin: %s", plugin);
    501	func(tep);
    502	return;
    503
    504 out_free:
    505	free(plugin);
    506}
    507
    508static void
    509load_plugins_dir(struct tep_handle *tep, const char *suffix,
    510		 const char *path,
    511		 void (*load_plugin)(struct tep_handle *tep,
    512				     const char *path,
    513				     const char *name,
    514				     void *data),
    515		 void *data)
    516{
    517	struct dirent *dent;
    518	struct stat st;
    519	DIR *dir;
    520	int ret;
    521
    522	ret = stat(path, &st);
    523	if (ret < 0)
    524		return;
    525
    526	if (!S_ISDIR(st.st_mode))
    527		return;
    528
    529	dir = opendir(path);
    530	if (!dir)
    531		return;
    532
    533	while ((dent = readdir(dir))) {
    534		const char *name = dent->d_name;
    535
    536		if (strcmp(name, ".") == 0 ||
    537		    strcmp(name, "..") == 0)
    538			continue;
    539
    540		/* Only load plugins that end in suffix */
    541		if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
    542			continue;
    543
    544		load_plugin(tep, path, name, data);
    545	}
    546
    547	closedir(dir);
    548}
    549
    550/**
    551 * tep_load_plugins_hook - call a user specified callback to load a plugin
    552 * @tep: handler to traceevent context
    553 * @suffix: filter only plugin files with given suffix
    554 * @load_plugin: user specified callback, called for each plugin file
    555 * @data: custom context, passed to @load_plugin
    556 *
    557 * Searches for traceevent plugin files and calls @load_plugin for each
    558 * The order of plugins search is:
    559 *  - Directories, specified in @tep->plugins_dir and priority TEP_PLUGIN_FIRST
    560 *  - Directory, specified at compile time with PLUGIN_TRACEEVENT_DIR
    561 *  - Directory, specified by environment variable TRACEEVENT_PLUGIN_DIR
    562 *  - In user's home: ~/.local/lib/traceevent/plugins/
    563 *  - Directories, specified in @tep->plugins_dir and priority TEP_PLUGIN_LAST
    564 *
    565 */
    566void tep_load_plugins_hook(struct tep_handle *tep, const char *suffix,
    567			   void (*load_plugin)(struct tep_handle *tep,
    568					       const char *path,
    569					       const char *name,
    570					       void *data),
    571			   void *data)
    572{
    573	struct tep_plugins_dir *dir = NULL;
    574	char *home;
    575	char *path;
    576	char *envdir;
    577	int ret;
    578
    579	if (tep && tep->flags & TEP_DISABLE_PLUGINS)
    580		return;
    581
    582	if (tep)
    583		dir = tep->plugins_dir;
    584	while (dir) {
    585		if (dir->prio == TEP_PLUGIN_FIRST)
    586			load_plugins_dir(tep, suffix, dir->path,
    587					 load_plugin, data);
    588		dir = dir->next;
    589	}
    590
    591	/*
    592	 * If a system plugin directory was defined,
    593	 * check that first.
    594	 */
    595#ifdef PLUGIN_DIR
    596	if (!tep || !(tep->flags & TEP_DISABLE_SYS_PLUGINS))
    597		load_plugins_dir(tep, suffix, PLUGIN_DIR,
    598				 load_plugin, data);
    599#endif
    600
    601	/*
    602	 * Next let the environment-set plugin directory
    603	 * override the system defaults.
    604	 */
    605	envdir = getenv("TRACEEVENT_PLUGIN_DIR");
    606	if (envdir)
    607		load_plugins_dir(tep, suffix, envdir, load_plugin, data);
    608
    609	/*
    610	 * Now let the home directory override the environment
    611	 * or system defaults.
    612	 */
    613	home = getenv("HOME");
    614	if (!home)
    615		return;
    616
    617	ret = asprintf(&path, "%s/%s", home, LOCAL_PLUGIN_DIR);
    618	if (ret < 0) {
    619		warning("could not allocate plugin memory\n");
    620		return;
    621	}
    622
    623	load_plugins_dir(tep, suffix, path, load_plugin, data);
    624
    625	if (tep)
    626		dir = tep->plugins_dir;
    627	while (dir) {
    628		if (dir->prio == TEP_PLUGIN_LAST)
    629			load_plugins_dir(tep, suffix, dir->path,
    630					 load_plugin, data);
    631		dir = dir->next;
    632	}
    633
    634	free(path);
    635}
    636
    637struct tep_plugin_list*
    638tep_load_plugins(struct tep_handle *tep)
    639{
    640	struct tep_plugin_list *list = NULL;
    641
    642	tep_load_plugins_hook(tep, ".so", load_plugin, &list);
    643	return list;
    644}
    645
    646/**
    647 * tep_add_plugin_path - Add a new plugin directory.
    648 * @tep: Trace event handler.
    649 * @path: Path to a directory. All plugin files in that
    650 *	  directory will be loaded.
    651 *@prio: Load priority of the plugins in that directory.
    652 *
    653 * Returns -1 in case of an error, 0 otherwise.
    654 */
    655int tep_add_plugin_path(struct tep_handle *tep, char *path,
    656			enum tep_plugin_load_priority prio)
    657{
    658	struct tep_plugins_dir *dir;
    659
    660	if (!tep || !path)
    661		return -1;
    662
    663	dir = calloc(1, sizeof(*dir));
    664	if (!dir)
    665		return -1;
    666
    667	dir->path = strdup(path);
    668	if (!dir->path) {
    669		free(dir);
    670		return -1;
    671	}
    672	dir->prio = prio;
    673	dir->next = tep->plugins_dir;
    674	tep->plugins_dir = dir;
    675
    676	return 0;
    677}
    678
    679__hidden void free_tep_plugin_paths(struct tep_handle *tep)
    680{
    681	struct tep_plugins_dir *dir;
    682
    683	if (!tep)
    684		return;
    685
    686	dir = tep->plugins_dir;
    687	while (dir) {
    688		tep->plugins_dir = tep->plugins_dir->next;
    689		free(dir->path);
    690		free(dir);
    691		dir = tep->plugins_dir;
    692	}
    693}
    694
    695void
    696tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *tep)
    697{
    698	tep_plugin_unload_func func;
    699	struct tep_plugin_list *list;
    700
    701	while (plugin_list) {
    702		list = plugin_list;
    703		plugin_list = list->next;
    704		func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME);
    705		if (func)
    706			func(tep);
    707		dlclose(list->handle);
    708		free(list->name);
    709		free(list);
    710	}
    711}