|
@@ -18,6 +18,7 @@
|
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
*/
|
|
|
|
|
|
+#include <stdio.h>
|
|
|
#include <string.h>
|
|
|
#include <dlfcn.h>
|
|
|
#include <stdlib.h>
|
|
@@ -30,12 +31,207 @@
|
|
|
|
|
|
#define LOCAL_PLUGIN_DIR ".traceevent/plugins"
|
|
|
|
|
|
+static struct registered_plugin_options {
|
|
|
+ struct registered_plugin_options *next;
|
|
|
+ struct pevent_plugin_option *options;
|
|
|
+} *registered_options;
|
|
|
+
|
|
|
+static struct trace_plugin_options {
|
|
|
+ struct trace_plugin_options *next;
|
|
|
+ char *plugin;
|
|
|
+ char *option;
|
|
|
+ char *value;
|
|
|
+} *trace_plugin_options;
|
|
|
+
|
|
|
struct plugin_list {
|
|
|
struct plugin_list *next;
|
|
|
char *name;
|
|
|
void *handle;
|
|
|
};
|
|
|
|
|
|
+/**
|
|
|
+ * traceevent_plugin_list_options - get list of plugin options
|
|
|
+ *
|
|
|
+ * Returns an array of char strings that list the currently registered
|
|
|
+ * plugin options in the format of <plugin>:<option>. This list can be
|
|
|
+ * used by toggling the option.
|
|
|
+ *
|
|
|
+ * Returns NULL if there's no options registered. On error it returns
|
|
|
+ * INVALID_PLUGIN_LIST_OPTION
|
|
|
+ *
|
|
|
+ * Must be freed with traceevent_plugin_free_options_list().
|
|
|
+ */
|
|
|
+char **traceevent_plugin_list_options(void)
|
|
|
+{
|
|
|
+ struct registered_plugin_options *reg;
|
|
|
+ struct pevent_plugin_option *op;
|
|
|
+ char **list = NULL;
|
|
|
+ char *name;
|
|
|
+ int count = 0;
|
|
|
+
|
|
|
+ for (reg = registered_options; reg; reg = reg->next) {
|
|
|
+ for (op = reg->options; op->name; op++) {
|
|
|
+ char *alias = op->plugin_alias ? op->plugin_alias : op->file;
|
|
|
+ char **temp = list;
|
|
|
+
|
|
|
+ name = malloc(strlen(op->name) + strlen(alias) + 2);
|
|
|
+ if (!name)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ sprintf(name, "%s:%s", alias, op->name);
|
|
|
+ list = realloc(list, count + 2);
|
|
|
+ if (!list) {
|
|
|
+ list = temp;
|
|
|
+ free(name);
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ list[count++] = name;
|
|
|
+ list[count] = NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+
|
|
|
+ err:
|
|
|
+ while (--count >= 0)
|
|
|
+ free(list[count]);
|
|
|
+ free(list);
|
|
|
+
|
|
|
+ return INVALID_PLUGIN_LIST_OPTION;
|
|
|
+}
|
|
|
+
|
|
|
+void traceevent_plugin_free_options_list(char **list)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (!list)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (list == INVALID_PLUGIN_LIST_OPTION)
|
|
|
+ return;
|
|
|
+
|
|
|
+ for (i = 0; list[i]; i++)
|
|
|
+ free(list[i]);
|
|
|
+
|
|
|
+ free(list);
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+update_option(const char *file, struct pevent_plugin_option *option)
|
|
|
+{
|
|
|
+ struct trace_plugin_options *op;
|
|
|
+ char *plugin;
|
|
|
+
|
|
|
+ if (option->plugin_alias) {
|
|
|
+ plugin = strdup(option->plugin_alias);
|
|
|
+ if (!plugin)
|
|
|
+ return -1;
|
|
|
+ } else {
|
|
|
+ char *p;
|
|
|
+ plugin = strdup(file);
|
|
|
+ if (!plugin)
|
|
|
+ return -1;
|
|
|
+ p = strstr(plugin, ".");
|
|
|
+ if (p)
|
|
|
+ *p = '\0';
|
|
|
+ }
|
|
|
+
|
|
|
+ /* first look for named options */
|
|
|
+ for (op = trace_plugin_options; op; op = op->next) {
|
|
|
+ if (!op->plugin)
|
|
|
+ continue;
|
|
|
+ if (strcmp(op->plugin, plugin) != 0)
|
|
|
+ continue;
|
|
|
+ if (strcmp(op->option, option->name) != 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ option->value = op->value;
|
|
|
+ option->set ^= 1;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* first look for unnamed options */
|
|
|
+ for (op = trace_plugin_options; op; op = op->next) {
|
|
|
+ if (op->plugin)
|
|
|
+ continue;
|
|
|
+ if (strcmp(op->option, option->name) != 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ option->value = op->value;
|
|
|
+ option->set ^= 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ out:
|
|
|
+ free(plugin);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * traceevent_plugin_add_options - Add a set of options by a plugin
|
|
|
+ * @name: The name of the plugin adding the options
|
|
|
+ * @options: The set of options being loaded
|
|
|
+ *
|
|
|
+ * Sets the options with the values that have been added by user.
|
|
|
+ */
|
|
|
+int traceevent_plugin_add_options(const char *name,
|
|
|
+ struct pevent_plugin_option *options)
|
|
|
+{
|
|
|
+ struct registered_plugin_options *reg;
|
|
|
+
|
|
|
+ reg = malloc(sizeof(*reg));
|
|
|
+ if (!reg)
|
|
|
+ return -1;
|
|
|
+ reg->next = registered_options;
|
|
|
+ reg->options = options;
|
|
|
+ registered_options = reg;
|
|
|
+
|
|
|
+ while (options->name) {
|
|
|
+ update_option(name, options);
|
|
|
+ options++;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * traceevent_plugin_remove_options - remove plugin options that were registered
|
|
|
+ * @options: Options to removed that were registered with traceevent_plugin_add_options
|
|
|
+ */
|
|
|
+void traceevent_plugin_remove_options(struct pevent_plugin_option *options)
|
|
|
+{
|
|
|
+ struct registered_plugin_options **last;
|
|
|
+ struct registered_plugin_options *reg;
|
|
|
+
|
|
|
+ for (last = ®istered_options; *last; last = &(*last)->next) {
|
|
|
+ if ((*last)->options == options) {
|
|
|
+ reg = *last;
|
|
|
+ *last = reg->next;
|
|
|
+ free(reg);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * traceevent_print_plugins - print out the list of plugins loaded
|
|
|
+ * @s: the trace_seq descripter to write to
|
|
|
+ * @prefix: The prefix string to add before listing the option name
|
|
|
+ * @suffix: The suffix string ot append after the option name
|
|
|
+ * @list: The list of plugins (usually returned by traceevent_load_plugins()
|
|
|
+ *
|
|
|
+ * Writes to the trace_seq @s the list of plugins (files) that is
|
|
|
+ * returned by traceevent_load_plugins(). Use @prefix and @suffix for formating:
|
|
|
+ * @prefix = " ", @suffix = "\n".
|
|
|
+ */
|
|
|
+void traceevent_print_plugins(struct trace_seq *s,
|
|
|
+ const char *prefix, const char *suffix,
|
|
|
+ const struct plugin_list *list)
|
|
|
+{
|
|
|
+ while (list) {
|
|
|
+ trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
|
|
|
+ list = list->next;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
load_plugin(struct pevent *pevent, const char *path,
|
|
|
const char *file, void *data)
|