diff options
author | Jiri Olsa <jolsa@redhat.com> | 2013-12-03 08:09:16 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-12-04 13:16:44 -0500 |
commit | c877bbd8eceb14c5eac6779cc804fa8b34044736 (patch) | |
tree | 78993da56e8c22201cc32d90485c13c8408af910 /tools/lib | |
parent | a2cb3cf20e06ef119ae541c1a08dc1977f7f0fff (diff) |
tools lib traceevent: Add plugin support
Backporting plugin support for traceevent lib.
Backported from Steven Rostedt's trace-cmd repo (HEAD 0f2c2fb):
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git
It's now possible to use following interface to load plugins
(shared objects) to enhance pevent object functionality.
The plugin interface/hooks are as follows:
(taken from event-parse.h comments)
- 'pevent_plugin_loader' (required)
The function name to initialized the plugin.
int pevent_plugin_loader(struct pevent *pevent)
- 'pevent_plugin_unloader' (optional)
The function called just before unloading
int pevent_plugin_unloader(void)
- 'pevent_plugin_options' (optional)
Plugin options that can be set before loading
struct plugin_option pevent_plugin_options[] = {
{
.name = "option-name",
.plugin_alias = "overide-file-name", (optional)
.description = "description of option to show users",
},
{
.name = NULL,
},
};
Array must end with .name = NULL;
The plugin_alias (below) can be used to give a shorter
name to access the variable. Useful if a plugin handles
more than one event.
NOTE options support is not backported yet.
- 'pevent_plugin_alias' (optional)
The name to use for finding options (uses filename if not defined)
New traceevent functions are added to search and load
available plugins:
struct plugin_list*
traceevent_load_plugins(struct pevent *pevent)
- loads plusing for 'struct pevent' object and returns
loaded plugins list
void traceevent_unload_plugins(struct plugin_list *plugin_list);
- unload plugin list
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/1386076182-14484-3-git-send-email-jolsa@redhat.com
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/lib')
-rw-r--r-- | tools/lib/traceevent/Makefile | 6 | ||||
-rw-r--r-- | tools/lib/traceevent/event-parse.h | 5 | ||||
-rw-r--r-- | tools/lib/traceevent/event-plugin.c | 202 |
3 files changed, 212 insertions, 1 deletions
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index fc1502098595..2ccb5bc800e8 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile | |||
@@ -180,7 +180,11 @@ $(obj)/%.o: $(src)/%.c | |||
180 | %.o: $(src)/%.c | 180 | %.o: $(src)/%.c |
181 | $(Q)$(call do_compile) | 181 | $(Q)$(call do_compile) |
182 | 182 | ||
183 | PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o | 183 | PEVENT_LIB_OBJS = event-parse.o |
184 | PEVENT_LIB_OBJS += event-plugin.o | ||
185 | PEVENT_LIB_OBJS += trace-seq.o | ||
186 | PEVENT_LIB_OBJS += parse-filter.o | ||
187 | PEVENT_LIB_OBJS += parse-utils.o | ||
184 | PEVENT_LIB_OBJS += kbuffer-parse.o | 188 | PEVENT_LIB_OBJS += kbuffer-parse.o |
185 | 189 | ||
186 | ALL_OBJS = $(PEVENT_LIB_OBJS) | 190 | ALL_OBJS = $(PEVENT_LIB_OBJS) |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 8d73d2594f65..a28886066bcc 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
@@ -377,6 +377,11 @@ enum pevent_errno { | |||
377 | }; | 377 | }; |
378 | #undef _PE | 378 | #undef _PE |
379 | 379 | ||
380 | struct plugin_list; | ||
381 | |||
382 | struct plugin_list *traceevent_load_plugins(struct pevent *pevent); | ||
383 | void traceevent_unload_plugins(struct plugin_list *plugin_list); | ||
384 | |||
380 | struct cmdline; | 385 | struct cmdline; |
381 | struct cmdline_list; | 386 | struct cmdline_list; |
382 | struct func_map; | 387 | struct func_map; |
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c new file mode 100644 index 000000000000..d272d87aa7d4 --- /dev/null +++ b/tools/lib/traceevent/event-plugin.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | |||
21 | #include <string.h> | ||
22 | #include <dlfcn.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <sys/types.h> | ||
25 | #include <sys/stat.h> | ||
26 | #include <unistd.h> | ||
27 | #include <dirent.h> | ||
28 | #include "event-parse.h" | ||
29 | #include "event-utils.h" | ||
30 | |||
31 | #define LOCAL_PLUGIN_DIR ".traceevent/plugins" | ||
32 | |||
33 | struct plugin_list { | ||
34 | struct plugin_list *next; | ||
35 | char *name; | ||
36 | void *handle; | ||
37 | }; | ||
38 | |||
39 | static void | ||
40 | load_plugin(struct pevent *pevent, const char *path, | ||
41 | const char *file, void *data) | ||
42 | { | ||
43 | struct plugin_list **plugin_list = data; | ||
44 | pevent_plugin_load_func func; | ||
45 | struct plugin_list *list; | ||
46 | const char *alias; | ||
47 | char *plugin; | ||
48 | void *handle; | ||
49 | |||
50 | plugin = malloc_or_die(strlen(path) + strlen(file) + 2); | ||
51 | |||
52 | strcpy(plugin, path); | ||
53 | strcat(plugin, "/"); | ||
54 | strcat(plugin, file); | ||
55 | |||
56 | handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL); | ||
57 | if (!handle) { | ||
58 | warning("could not load plugin '%s'\n%s\n", | ||
59 | plugin, dlerror()); | ||
60 | goto out_free; | ||
61 | } | ||
62 | |||
63 | alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME); | ||
64 | if (!alias) | ||
65 | alias = file; | ||
66 | |||
67 | func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME); | ||
68 | if (!func) { | ||
69 | warning("could not find func '%s' in plugin '%s'\n%s\n", | ||
70 | PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror()); | ||
71 | goto out_free; | ||
72 | } | ||
73 | |||
74 | list = malloc_or_die(sizeof(*list)); | ||
75 | list->next = *plugin_list; | ||
76 | list->handle = handle; | ||
77 | list->name = plugin; | ||
78 | *plugin_list = list; | ||
79 | |||
80 | pr_stat("registering plugin: %s", plugin); | ||
81 | func(pevent); | ||
82 | return; | ||
83 | |||
84 | out_free: | ||
85 | free(plugin); | ||
86 | } | ||
87 | |||
88 | static void | ||
89 | load_plugins_dir(struct pevent *pevent, const char *suffix, | ||
90 | const char *path, | ||
91 | void (*load_plugin)(struct pevent *pevent, | ||
92 | const char *path, | ||
93 | const char *name, | ||
94 | void *data), | ||
95 | void *data) | ||
96 | { | ||
97 | struct dirent *dent; | ||
98 | struct stat st; | ||
99 | DIR *dir; | ||
100 | int ret; | ||
101 | |||
102 | ret = stat(path, &st); | ||
103 | if (ret < 0) | ||
104 | return; | ||
105 | |||
106 | if (!S_ISDIR(st.st_mode)) | ||
107 | return; | ||
108 | |||
109 | dir = opendir(path); | ||
110 | if (!dir) | ||
111 | return; | ||
112 | |||
113 | while ((dent = readdir(dir))) { | ||
114 | const char *name = dent->d_name; | ||
115 | |||
116 | if (strcmp(name, ".") == 0 || | ||
117 | strcmp(name, "..") == 0) | ||
118 | continue; | ||
119 | |||
120 | /* Only load plugins that end in suffix */ | ||
121 | if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0) | ||
122 | continue; | ||
123 | |||
124 | load_plugin(pevent, path, name, data); | ||
125 | } | ||
126 | |||
127 | closedir(dir); | ||
128 | } | ||
129 | |||
130 | static void | ||
131 | load_plugins(struct pevent *pevent, const char *suffix, | ||
132 | void (*load_plugin)(struct pevent *pevent, | ||
133 | const char *path, | ||
134 | const char *name, | ||
135 | void *data), | ||
136 | void *data) | ||
137 | { | ||
138 | char *home; | ||
139 | char *path; | ||
140 | char *envdir; | ||
141 | |||
142 | /* | ||
143 | * If a system plugin directory was defined, | ||
144 | * check that first. | ||
145 | */ | ||
146 | #ifdef PLUGIN_DIR | ||
147 | load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data); | ||
148 | #endif | ||
149 | |||
150 | /* | ||
151 | * Next let the environment-set plugin directory | ||
152 | * override the system defaults. | ||
153 | */ | ||
154 | envdir = getenv("TRACEEVENT_PLUGIN_DIR"); | ||
155 | if (envdir) | ||
156 | load_plugins_dir(pevent, suffix, envdir, load_plugin, data); | ||
157 | |||
158 | /* | ||
159 | * Now let the home directory override the environment | ||
160 | * or system defaults. | ||
161 | */ | ||
162 | home = getenv("HOME"); | ||
163 | if (!home) | ||
164 | return; | ||
165 | |||
166 | path = malloc_or_die(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2); | ||
167 | |||
168 | strcpy(path, home); | ||
169 | strcat(path, "/"); | ||
170 | strcat(path, LOCAL_PLUGIN_DIR); | ||
171 | |||
172 | load_plugins_dir(pevent, suffix, path, load_plugin, data); | ||
173 | |||
174 | free(path); | ||
175 | } | ||
176 | |||
177 | struct plugin_list* | ||
178 | traceevent_load_plugins(struct pevent *pevent) | ||
179 | { | ||
180 | struct plugin_list *list = NULL; | ||
181 | |||
182 | load_plugins(pevent, ".so", load_plugin, &list); | ||
183 | return list; | ||
184 | } | ||
185 | |||
186 | void | ||
187 | traceevent_unload_plugins(struct plugin_list *plugin_list) | ||
188 | { | ||
189 | pevent_plugin_unload_func func; | ||
190 | struct plugin_list *list; | ||
191 | |||
192 | while (plugin_list) { | ||
193 | list = plugin_list; | ||
194 | plugin_list = list->next; | ||
195 | func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME); | ||
196 | if (func) | ||
197 | func(); | ||
198 | dlclose(list->handle); | ||
199 | free(list->name); | ||
200 | free(list); | ||
201 | } | ||
202 | } | ||