hc
2023-12-09 b22da3d8526a935aa31e086e63f60ff3246cb61c
kernel/tools/lib/traceevent/event-plugin.c
....@@ -13,8 +13,11 @@
1313 #include <sys/stat.h>
1414 #include <unistd.h>
1515 #include <dirent.h>
16
+#include <errno.h>
1617 #include "event-parse.h"
18
+#include "event-parse-local.h"
1719 #include "event-utils.h"
20
+#include "trace-seq.h"
1821
1922 #define LOCAL_PLUGIN_DIR ".local/lib/traceevent/plugins/"
2023
....@@ -30,10 +33,16 @@
3033 char *value;
3134 } *trace_plugin_options;
3235
33
-struct plugin_list {
34
- struct plugin_list *next;
36
+struct tep_plugin_list {
37
+ struct tep_plugin_list *next;
3538 char *name;
3639 void *handle;
40
+};
41
+
42
+struct tep_plugins_dir {
43
+ struct tep_plugins_dir *next;
44
+ char *path;
45
+ enum tep_plugin_load_priority prio;
3746 };
3847
3948 static void lower_case(char *str)
....@@ -245,6 +254,170 @@
245254 }
246255 }
247256
257
+static 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
+
273
+static struct tep_plugin_option *
274
+find_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
+
299
+static 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
+ */
319
+int 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
+
381
+out_free:
382
+ free(plugin);
383
+ free(option_str);
384
+ return -ENOMEM;
385
+}
386
+
387
+static 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
+ */
400
+void 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
+
248421 /**
249422 * tep_print_plugins - print out the list of plugins loaded
250423 * @s: the trace_seq descripter to write to
....@@ -258,7 +431,7 @@
258431 */
259432 void tep_print_plugins(struct trace_seq *s,
260433 const char *prefix, const char *suffix,
261
- const struct plugin_list *list)
434
+ const struct tep_plugin_list *list)
262435 {
263436 while (list) {
264437 trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
....@@ -267,12 +440,13 @@
267440 }
268441
269442 static void
270
-load_plugin(struct tep_handle *pevent, const char *path,
443
+load_plugin(struct tep_handle *tep, const char *path,
271444 const char *file, void *data)
272445 {
273
- struct plugin_list **plugin_list = data;
446
+ struct tep_plugin_list **plugin_list = data;
447
+ struct tep_plugin_option *options;
274448 tep_plugin_load_func func;
275
- struct plugin_list *list;
449
+ struct tep_plugin_list *list;
276450 const char *alias;
277451 char *plugin;
278452 void *handle;
....@@ -295,6 +469,16 @@
295469 if (!alias)
296470 alias = file;
297471
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
+
298482 func = dlsym(handle, TEP_PLUGIN_LOADER_NAME);
299483 if (!func) {
300484 warning("could not find func '%s' in plugin '%s'\n%s\n",
....@@ -314,7 +498,7 @@
314498 *plugin_list = list;
315499
316500 pr_stat("registering plugin: %s", plugin);
317
- func(pevent);
501
+ func(tep);
318502 return;
319503
320504 out_free:
....@@ -322,9 +506,9 @@
322506 }
323507
324508 static void
325
-load_plugins_dir(struct tep_handle *pevent, const char *suffix,
509
+load_plugins_dir(struct tep_handle *tep, const char *suffix,
326510 const char *path,
327
- void (*load_plugin)(struct tep_handle *pevent,
511
+ void (*load_plugin)(struct tep_handle *tep,
328512 const char *path,
329513 const char *name,
330514 void *data),
....@@ -357,35 +541,60 @@
357541 if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
358542 continue;
359543
360
- load_plugin(pevent, path, name, data);
544
+ load_plugin(tep, path, name, data);
361545 }
362546
363547 closedir(dir);
364548 }
365549
366
-static void
367
-load_plugins(struct tep_handle *pevent, const char *suffix,
368
- void (*load_plugin)(struct tep_handle *pevent,
369
- const char *path,
370
- const char *name,
371
- void *data),
372
- void *data)
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
+ */
566
+void 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)
373572 {
573
+ struct tep_plugins_dir *dir = NULL;
374574 char *home;
375575 char *path;
376576 char *envdir;
377577 int ret;
378578
379
- if (pevent->flags & TEP_DISABLE_PLUGINS)
579
+ if (tep && tep->flags & TEP_DISABLE_PLUGINS)
380580 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
+ }
381590
382591 /*
383592 * If a system plugin directory was defined,
384593 * check that first.
385594 */
386595 #ifdef PLUGIN_DIR
387
- if (!(pevent->flags & TEP_DISABLE_SYS_PLUGINS))
388
- load_plugins_dir(pevent, suffix, PLUGIN_DIR,
596
+ if (!tep || !(tep->flags & TEP_DISABLE_SYS_PLUGINS))
597
+ load_plugins_dir(tep, suffix, PLUGIN_DIR,
389598 load_plugin, data);
390599 #endif
391600
....@@ -395,7 +604,7 @@
395604 */
396605 envdir = getenv("TRACEEVENT_PLUGIN_DIR");
397606 if (envdir)
398
- load_plugins_dir(pevent, suffix, envdir, load_plugin, data);
607
+ load_plugins_dir(tep, suffix, envdir, load_plugin, data);
399608
400609 /*
401610 * Now let the home directory override the environment
....@@ -411,32 +620,90 @@
411620 return;
412621 }
413622
414
- load_plugins_dir(pevent, suffix, path, load_plugin, data);
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
+ }
415633
416634 free(path);
417635 }
418636
419
-struct plugin_list*
420
-tep_load_plugins(struct tep_handle *pevent)
637
+struct tep_plugin_list*
638
+tep_load_plugins(struct tep_handle *tep)
421639 {
422
- struct plugin_list *list = NULL;
640
+ struct tep_plugin_list *list = NULL;
423641
424
- load_plugins(pevent, ".so", load_plugin, &list);
642
+ tep_load_plugins_hook(tep, ".so", load_plugin, &list);
425643 return list;
426644 }
427645
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
+ */
655
+int 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
+
428695 void
429
-tep_unload_plugins(struct plugin_list *plugin_list, struct tep_handle *pevent)
696
+tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *tep)
430697 {
431698 tep_plugin_unload_func func;
432
- struct plugin_list *list;
699
+ struct tep_plugin_list *list;
433700
434701 while (plugin_list) {
435702 list = plugin_list;
436703 plugin_list = list->next;
437704 func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME);
438705 if (func)
439
- func(pevent);
706
+ func(tep);
440707 dlclose(list->handle);
441708 free(list->name);
442709 free(list);