aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@redhat.com>2013-12-03 08:09:16 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2013-12-04 13:16:44 -0500
commitc877bbd8eceb14c5eac6779cc804fa8b34044736 (patch)
tree78993da56e8c22201cc32d90485c13c8408af910 /tools/lib
parenta2cb3cf20e06ef119ae541c1a08dc1977f7f0fff (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/Makefile6
-rw-r--r--tools/lib/traceevent/event-parse.h5
-rw-r--r--tools/lib/traceevent/event-plugin.c202
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
183PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o 183PEVENT_LIB_OBJS = event-parse.o
184PEVENT_LIB_OBJS += event-plugin.o
185PEVENT_LIB_OBJS += trace-seq.o
186PEVENT_LIB_OBJS += parse-filter.o
187PEVENT_LIB_OBJS += parse-utils.o
184PEVENT_LIB_OBJS += kbuffer-parse.o 188PEVENT_LIB_OBJS += kbuffer-parse.o
185 189
186ALL_OBJS = $(PEVENT_LIB_OBJS) 190ALL_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
380struct plugin_list;
381
382struct plugin_list *traceevent_load_plugins(struct pevent *pevent);
383void traceevent_unload_plugins(struct plugin_list *plugin_list);
384
380struct cmdline; 385struct cmdline;
381struct cmdline_list; 386struct cmdline_list;
382struct func_map; 387struct 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
33struct plugin_list {
34 struct plugin_list *next;
35 char *name;
36 void *handle;
37};
38
39static void
40load_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
88static void
89load_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
130static void
131load_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
177struct plugin_list*
178traceevent_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
186void
187traceevent_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}