Message ID | 20200702185704.092654084@goodmis.org (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | tools lib traceevent: Patches from the trace-cmd repo | expand |
On Fri, Jul 3, 2020 at 3:57 AM Steven Rostedt <rostedt@goodmis.org> wrote: > > From: "Tzvetomir Stoyanov (VMware)" <tz.stoyanov@gmail.com> > > Add tep_plugin_add_option() and tep_plugin_print_options() to lib traceevent > library that allows plugins to have their own options. For example, the > function plugin by default does not print the parent, as it uses the parent > to do the indenting. The "parent" option is created by the function plugin > that will print the parent of the function like it does in the trace file. > > The tep_plugin_print_options() will print out the list of options that a > plugin has defined. > > Link: http://lore.kernel.org/linux-trace-devel/20190802110101.14759-3-tz.stoyanov@gmail.com > Link: http://lore.kernel.org/linux-trace-devel/20200625100516.365338-5-tz.stoyanov@gmail.com > > Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com> > Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> > --- > tools/lib/traceevent/event-parse.h | 2 + > tools/lib/traceevent/event-plugin.c | 172 ++++++++++++++++++++++++++++ > 2 files changed, 174 insertions(+) > > diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h > index 776c7c24ee79..02c0438527de 100644 > --- a/tools/lib/traceevent/event-parse.h > +++ b/tools/lib/traceevent/event-parse.h > @@ -406,7 +406,9 @@ char **tep_plugin_list_options(void); > void tep_plugin_free_options_list(char **list); > int tep_plugin_add_options(const char *name, > struct tep_plugin_option *options); > +int tep_plugin_add_option(const char *name, const char *val); > void tep_plugin_remove_options(struct tep_plugin_option *options); > +void tep_plugin_print_options(struct trace_seq *s); > void tep_print_plugins(struct trace_seq *s, > const char *prefix, const char *suffix, > const struct tep_plugin_list *list); > diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c > index b53d9a53bcf9..e8f4329ba8e0 100644 > --- a/tools/lib/traceevent/event-plugin.c > +++ b/tools/lib/traceevent/event-plugin.c > @@ -13,6 +13,7 @@ > #include <sys/stat.h> > #include <unistd.h> > #include <dirent.h> > +#include <errno.h> > #include "event-parse.h" > #include "event-parse-local.h" > #include "event-utils.h" > @@ -247,6 +248,166 @@ void tep_plugin_remove_options(struct tep_plugin_option *options) > } > } > > +static void parse_option_name(char **option, char **plugin) > +{ > + char *p; > + > + *plugin = NULL; > + > + if ((p = strstr(*option, ":"))) { > + *plugin = *option; > + *p = '\0'; > + *option = strdup(p + 1); > + if (!*option) > + return; It needs to pass the error somehow.. > + } > +} > + > +static struct tep_plugin_option * > +find_registered_option(const char *plugin, const char *option) > +{ > + struct registered_plugin_options *reg; > + struct tep_plugin_option *op; > + const char *op_plugin; > + > + for (reg = registered_options; reg; reg = reg->next) { > + for (op = reg->options; op->name; op++) { > + if (op->plugin_alias) > + op_plugin = op->plugin_alias; > + else > + op_plugin = op->file; > + > + if (plugin && strcmp(plugin, op_plugin) != 0) > + continue; > + if (strcmp(option, op->name) != 0) > + continue; > + > + return op; > + } > + } > + > + return NULL; > +} > + > +static int process_option(const char *plugin, const char *option, const char *val) > +{ > + struct tep_plugin_option *op; > + > + op = find_registered_option(plugin, option); > + if (!op) > + return 0; > + > + return update_option_value(op, val); > +} > + > +/** > + * tep_plugin_add_option - add an option/val pair to set plugin options > + * @name: The name of the option (format: <plugin>:<option> or just <option>) > + * @val: (optiona) the value for the option Typo. > + * > + * Modify a plugin option. If @val is given than the value of the option > + * is set (note, some options just take a boolean, so @val must be either > + * "1" or "0" or "true" or "false"). > + */ > +int tep_plugin_add_option(const char *name, const char *val) > +{ > + struct trace_plugin_options *op; > + char *option_str; > + char *plugin; > + > + option_str = strdup(name); > + if (!option_str) > + return -ENOMEM; > + > + parse_option_name(&option_str, &plugin); > + > + /* If the option exists, update the val */ > + for (op = trace_plugin_options; op; op = op->next) { > + /* Both must be NULL or not NULL */ > + if ((!plugin || !op->plugin) && plugin != op->plugin) > + continue; > + if (plugin && strcmp(plugin, op->plugin) != 0) > + continue; > + if (strcmp(op->option, option_str) != 0) > + continue; > + > + /* update option */ > + free(op->value); > + if (val) { > + op->value = strdup(val); > + if (!op->value) > + goto out_free; > + } else > + op->value = NULL; > + > + /* plugin and option_str don't get freed at the end */ > + free(plugin); > + free(option_str); > + > + plugin = op->plugin; > + option_str = op->option; > + break; > + } > + > + /* If not found, create */ > + if (!op) { > + op = malloc(sizeof(*op)); > + if (!op) > + return -ENOMEM; goto out_free ? > + memset(op, 0, sizeof(*op)); > + op->next = trace_plugin_options; > + trace_plugin_options = op; I think it's better doing this after setting the value below.. > + > + op->plugin = plugin; > + op->option = option_str; > + > + if (val) { > + op->value = strdup(val); > + if (!op->value) > + goto out_free; The option_str will be freed and op will have a dangling pointer.. > + } > + } > + > + return process_option(plugin, option_str, val); > + out_free: > + free(option_str); Why not free plugin too? Thanks Namhyung > + return -ENOMEM; > +} > + > +static void print_op_data(struct trace_seq *s, const char *name, > + const char *op) > +{ > + if (op) > + trace_seq_printf(s, "%8s:\t%s\n", name, op); > +} > + > +/** > + * tep_plugin_print_options - print out the registered plugin options > + * @s: The trace_seq descriptor to write the plugin options into > + * > + * Writes a list of options into trace_seq @s. > + */ > +void tep_plugin_print_options(struct trace_seq *s) > +{ > + struct registered_plugin_options *reg; > + struct tep_plugin_option *op; > + > + for (reg = registered_options; reg; reg = reg->next) { > + if (reg != registered_options) > + trace_seq_printf(s, "============\n"); > + for (op = reg->options; op->name; op++) { > + if (op != reg->options) > + trace_seq_printf(s, "------------\n"); > + print_op_data(s, "file", op->file); > + print_op_data(s, "plugin", op->plugin_alias); > + print_op_data(s, "option", op->name); > + print_op_data(s, "desc", op->description); > + print_op_data(s, "value", op->value); > + trace_seq_printf(s, "%8s:\t%d\n", "set", op->set); > + } > + } > +} > + > /** > * tep_print_plugins - print out the list of plugins loaded > * @s: the trace_seq descripter to write to > @@ -273,6 +434,7 @@ load_plugin(struct tep_handle *tep, const char *path, > const char *file, void *data) > { > struct tep_plugin_list **plugin_list = data; > + struct tep_plugin_option *options; > tep_plugin_load_func func; > struct tep_plugin_list *list; > const char *alias; > @@ -297,6 +459,16 @@ load_plugin(struct tep_handle *tep, const char *path, > if (!alias) > alias = file; > > + options = dlsym(handle, TEP_PLUGIN_OPTIONS_NAME); > + if (options) { > + while (options->name) { > + ret = update_option(alias, options); > + if (ret < 0) > + goto out_free; > + options++; > + } > + } > + > func = dlsym(handle, TEP_PLUGIN_LOADER_NAME); > if (!func) { > warning("could not find func '%s' in plugin '%s'\n%s\n", > -- > 2.26.2 > >
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 776c7c24ee79..02c0438527de 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -406,7 +406,9 @@ char **tep_plugin_list_options(void); void tep_plugin_free_options_list(char **list); int tep_plugin_add_options(const char *name, struct tep_plugin_option *options); +int tep_plugin_add_option(const char *name, const char *val); void tep_plugin_remove_options(struct tep_plugin_option *options); +void tep_plugin_print_options(struct trace_seq *s); void tep_print_plugins(struct trace_seq *s, const char *prefix, const char *suffix, const struct tep_plugin_list *list); diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c index b53d9a53bcf9..e8f4329ba8e0 100644 --- a/tools/lib/traceevent/event-plugin.c +++ b/tools/lib/traceevent/event-plugin.c @@ -13,6 +13,7 @@ #include <sys/stat.h> #include <unistd.h> #include <dirent.h> +#include <errno.h> #include "event-parse.h" #include "event-parse-local.h" #include "event-utils.h" @@ -247,6 +248,166 @@ void tep_plugin_remove_options(struct tep_plugin_option *options) } } +static void parse_option_name(char **option, char **plugin) +{ + char *p; + + *plugin = NULL; + + if ((p = strstr(*option, ":"))) { + *plugin = *option; + *p = '\0'; + *option = strdup(p + 1); + if (!*option) + return; + } +} + +static struct tep_plugin_option * +find_registered_option(const char *plugin, const char *option) +{ + struct registered_plugin_options *reg; + struct tep_plugin_option *op; + const char *op_plugin; + + for (reg = registered_options; reg; reg = reg->next) { + for (op = reg->options; op->name; op++) { + if (op->plugin_alias) + op_plugin = op->plugin_alias; + else + op_plugin = op->file; + + if (plugin && strcmp(plugin, op_plugin) != 0) + continue; + if (strcmp(option, op->name) != 0) + continue; + + return op; + } + } + + return NULL; +} + +static int process_option(const char *plugin, const char *option, const char *val) +{ + struct tep_plugin_option *op; + + op = find_registered_option(plugin, option); + if (!op) + return 0; + + return update_option_value(op, val); +} + +/** + * tep_plugin_add_option - add an option/val pair to set plugin options + * @name: The name of the option (format: <plugin>:<option> or just <option>) + * @val: (optiona) the value for the option + * + * Modify a plugin option. If @val is given than the value of the option + * is set (note, some options just take a boolean, so @val must be either + * "1" or "0" or "true" or "false"). + */ +int tep_plugin_add_option(const char *name, const char *val) +{ + struct trace_plugin_options *op; + char *option_str; + char *plugin; + + option_str = strdup(name); + if (!option_str) + return -ENOMEM; + + parse_option_name(&option_str, &plugin); + + /* If the option exists, update the val */ + for (op = trace_plugin_options; op; op = op->next) { + /* Both must be NULL or not NULL */ + if ((!plugin || !op->plugin) && plugin != op->plugin) + continue; + if (plugin && strcmp(plugin, op->plugin) != 0) + continue; + if (strcmp(op->option, option_str) != 0) + continue; + + /* update option */ + free(op->value); + if (val) { + op->value = strdup(val); + if (!op->value) + goto out_free; + } else + op->value = NULL; + + /* plugin and option_str don't get freed at the end */ + free(plugin); + free(option_str); + + plugin = op->plugin; + option_str = op->option; + break; + } + + /* If not found, create */ + if (!op) { + op = malloc(sizeof(*op)); + if (!op) + return -ENOMEM; + memset(op, 0, sizeof(*op)); + op->next = trace_plugin_options; + trace_plugin_options = op; + + op->plugin = plugin; + op->option = option_str; + + if (val) { + op->value = strdup(val); + if (!op->value) + goto out_free; + } + } + + return process_option(plugin, option_str, val); + out_free: + free(option_str); + return -ENOMEM; +} + +static void print_op_data(struct trace_seq *s, const char *name, + const char *op) +{ + if (op) + trace_seq_printf(s, "%8s:\t%s\n", name, op); +} + +/** + * tep_plugin_print_options - print out the registered plugin options + * @s: The trace_seq descriptor to write the plugin options into + * + * Writes a list of options into trace_seq @s. + */ +void tep_plugin_print_options(struct trace_seq *s) +{ + struct registered_plugin_options *reg; + struct tep_plugin_option *op; + + for (reg = registered_options; reg; reg = reg->next) { + if (reg != registered_options) + trace_seq_printf(s, "============\n"); + for (op = reg->options; op->name; op++) { + if (op != reg->options) + trace_seq_printf(s, "------------\n"); + print_op_data(s, "file", op->file); + print_op_data(s, "plugin", op->plugin_alias); + print_op_data(s, "option", op->name); + print_op_data(s, "desc", op->description); + print_op_data(s, "value", op->value); + trace_seq_printf(s, "%8s:\t%d\n", "set", op->set); + } + } +} + /** * tep_print_plugins - print out the list of plugins loaded * @s: the trace_seq descripter to write to @@ -273,6 +434,7 @@ load_plugin(struct tep_handle *tep, const char *path, const char *file, void *data) { struct tep_plugin_list **plugin_list = data; + struct tep_plugin_option *options; tep_plugin_load_func func; struct tep_plugin_list *list; const char *alias; @@ -297,6 +459,16 @@ load_plugin(struct tep_handle *tep, const char *path, if (!alias) alias = file; + options = dlsym(handle, TEP_PLUGIN_OPTIONS_NAME); + if (options) { + while (options->name) { + ret = update_option(alias, options); + if (ret < 0) + goto out_free; + options++; + } + } + func = dlsym(handle, TEP_PLUGIN_LOADER_NAME); if (!func) { warning("could not find func '%s' in plugin '%s'\n%s\n",