aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/traceevent
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lib/traceevent')
-rw-r--r--tools/lib/traceevent/event-parse.c113
-rw-r--r--tools/lib/traceevent/event-parse.h25
-rw-r--r--tools/lib/traceevent/event-plugin.c203
-rw-r--r--tools/lib/traceevent/plugin_function.c43
4 files changed, 374 insertions, 10 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index b83184f2d484..93825a17dcce 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -765,6 +765,9 @@ static void free_arg(struct print_arg *arg)
765 case PRINT_BSTRING: 765 case PRINT_BSTRING:
766 free(arg->string.string); 766 free(arg->string.string);
767 break; 767 break;
768 case PRINT_BITMASK:
769 free(arg->bitmask.bitmask);
770 break;
768 case PRINT_DYNAMIC_ARRAY: 771 case PRINT_DYNAMIC_ARRAY:
769 free(arg->dynarray.index); 772 free(arg->dynarray.index);
770 break; 773 break;
@@ -2268,6 +2271,7 @@ static int arg_num_eval(struct print_arg *arg, long long *val)
2268 case PRINT_FIELD ... PRINT_SYMBOL: 2271 case PRINT_FIELD ... PRINT_SYMBOL:
2269 case PRINT_STRING: 2272 case PRINT_STRING:
2270 case PRINT_BSTRING: 2273 case PRINT_BSTRING:
2274 case PRINT_BITMASK:
2271 default: 2275 default:
2272 do_warning("invalid eval type %d", arg->type); 2276 do_warning("invalid eval type %d", arg->type);
2273 ret = 0; 2277 ret = 0;
@@ -2296,6 +2300,7 @@ static char *arg_eval (struct print_arg *arg)
2296 case PRINT_FIELD ... PRINT_SYMBOL: 2300 case PRINT_FIELD ... PRINT_SYMBOL:
2297 case PRINT_STRING: 2301 case PRINT_STRING:
2298 case PRINT_BSTRING: 2302 case PRINT_BSTRING:
2303 case PRINT_BITMASK:
2299 default: 2304 default:
2300 do_warning("invalid eval type %d", arg->type); 2305 do_warning("invalid eval type %d", arg->type);
2301 break; 2306 break;
@@ -2683,6 +2688,35 @@ process_str(struct event_format *event __maybe_unused, struct print_arg *arg,
2683 return EVENT_ERROR; 2688 return EVENT_ERROR;
2684} 2689}
2685 2690
2691static enum event_type
2692process_bitmask(struct event_format *event __maybe_unused, struct print_arg *arg,
2693 char **tok)
2694{
2695 enum event_type type;
2696 char *token;
2697
2698 if (read_expect_type(EVENT_ITEM, &token) < 0)
2699 goto out_free;
2700
2701 arg->type = PRINT_BITMASK;
2702 arg->bitmask.bitmask = token;
2703 arg->bitmask.offset = -1;
2704
2705 if (read_expected(EVENT_DELIM, ")") < 0)
2706 goto out_err;
2707
2708 type = read_token(&token);
2709 *tok = token;
2710
2711 return type;
2712
2713 out_free:
2714 free_token(token);
2715 out_err:
2716 *tok = NULL;
2717 return EVENT_ERROR;
2718}
2719
2686static struct pevent_function_handler * 2720static struct pevent_function_handler *
2687find_func_handler(struct pevent *pevent, char *func_name) 2721find_func_handler(struct pevent *pevent, char *func_name)
2688{ 2722{
@@ -2797,6 +2831,10 @@ process_function(struct event_format *event, struct print_arg *arg,
2797 free_token(token); 2831 free_token(token);
2798 return process_str(event, arg, tok); 2832 return process_str(event, arg, tok);
2799 } 2833 }
2834 if (strcmp(token, "__get_bitmask") == 0) {
2835 free_token(token);
2836 return process_bitmask(event, arg, tok);
2837 }
2800 if (strcmp(token, "__get_dynamic_array") == 0) { 2838 if (strcmp(token, "__get_dynamic_array") == 0) {
2801 free_token(token); 2839 free_token(token);
2802 return process_dynamic_array(event, arg, tok); 2840 return process_dynamic_array(event, arg, tok);
@@ -3324,6 +3362,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg
3324 return eval_type(val, arg, 0); 3362 return eval_type(val, arg, 0);
3325 case PRINT_STRING: 3363 case PRINT_STRING:
3326 case PRINT_BSTRING: 3364 case PRINT_BSTRING:
3365 case PRINT_BITMASK:
3327 return 0; 3366 return 0;
3328 case PRINT_FUNC: { 3367 case PRINT_FUNC: {
3329 struct trace_seq s; 3368 struct trace_seq s;
@@ -3556,6 +3595,60 @@ static void print_str_to_seq(struct trace_seq *s, const char *format,
3556 trace_seq_printf(s, format, str); 3595 trace_seq_printf(s, format, str);
3557} 3596}
3558 3597
3598static void print_bitmask_to_seq(struct pevent *pevent,
3599 struct trace_seq *s, const char *format,
3600 int len_arg, const void *data, int size)
3601{
3602 int nr_bits = size * 8;
3603 int str_size = (nr_bits + 3) / 4;
3604 int len = 0;
3605 char buf[3];
3606 char *str;
3607 int index;
3608 int i;
3609
3610 /*
3611 * The kernel likes to put in commas every 32 bits, we
3612 * can do the same.
3613 */
3614 str_size += (nr_bits - 1) / 32;
3615
3616 str = malloc(str_size + 1);
3617 if (!str) {
3618 do_warning("%s: not enough memory!", __func__);
3619 return;
3620 }
3621 str[str_size] = 0;
3622
3623 /* Start out with -2 for the two chars per byte */
3624 for (i = str_size - 2; i >= 0; i -= 2) {
3625 /*
3626 * data points to a bit mask of size bytes.
3627 * In the kernel, this is an array of long words, thus
3628 * endianess is very important.
3629 */
3630 if (pevent->file_bigendian)
3631 index = size - (len + 1);
3632 else
3633 index = len;
3634
3635 snprintf(buf, 3, "%02x", *((unsigned char *)data + index));
3636 memcpy(str + i, buf, 2);
3637 len++;
3638 if (!(len & 3) && i > 0) {
3639 i--;
3640 str[i] = ',';
3641 }
3642 }
3643
3644 if (len_arg >= 0)
3645 trace_seq_printf(s, format, len_arg, str);
3646 else
3647 trace_seq_printf(s, format, str);
3648
3649 free(str);
3650}
3651
3559static void print_str_arg(struct trace_seq *s, void *data, int size, 3652static void print_str_arg(struct trace_seq *s, void *data, int size,
3560 struct event_format *event, const char *format, 3653 struct event_format *event, const char *format,
3561 int len_arg, struct print_arg *arg) 3654 int len_arg, struct print_arg *arg)
@@ -3691,6 +3784,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
3691 case PRINT_BSTRING: 3784 case PRINT_BSTRING:
3692 print_str_to_seq(s, format, len_arg, arg->string.string); 3785 print_str_to_seq(s, format, len_arg, arg->string.string);
3693 break; 3786 break;
3787 case PRINT_BITMASK: {
3788 int bitmask_offset;
3789 int bitmask_size;
3790
3791 if (arg->bitmask.offset == -1) {
3792 struct format_field *f;
3793
3794 f = pevent_find_any_field(event, arg->bitmask.bitmask);
3795 arg->bitmask.offset = f->offset;
3796 }
3797 bitmask_offset = data2host4(pevent, data + arg->bitmask.offset);
3798 bitmask_size = bitmask_offset >> 16;
3799 bitmask_offset &= 0xffff;
3800 print_bitmask_to_seq(pevent, s, format, len_arg,
3801 data + bitmask_offset, bitmask_size);
3802 break;
3803 }
3694 case PRINT_OP: 3804 case PRINT_OP:
3695 /* 3805 /*
3696 * The only op for string should be ? : 3806 * The only op for string should be ? :
@@ -4822,6 +4932,9 @@ static void print_args(struct print_arg *args)
4822 case PRINT_BSTRING: 4932 case PRINT_BSTRING:
4823 printf("__get_str(%s)", args->string.string); 4933 printf("__get_str(%s)", args->string.string);
4824 break; 4934 break;
4935 case PRINT_BITMASK:
4936 printf("__get_bitmask(%s)", args->bitmask.bitmask);
4937 break;
4825 case PRINT_TYPE: 4938 case PRINT_TYPE:
4826 printf("(%s)", args->typecast.type); 4939 printf("(%s)", args->typecast.type);
4827 print_args(args->typecast.item); 4940 print_args(args->typecast.item);
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index feab94281634..7a3873ff9a4f 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -107,8 +107,8 @@ typedef int (*pevent_event_handler_func)(struct trace_seq *s,
107typedef int (*pevent_plugin_load_func)(struct pevent *pevent); 107typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
108typedef int (*pevent_plugin_unload_func)(struct pevent *pevent); 108typedef int (*pevent_plugin_unload_func)(struct pevent *pevent);
109 109
110struct plugin_option { 110struct pevent_plugin_option {
111 struct plugin_option *next; 111 struct pevent_plugin_option *next;
112 void *handle; 112 void *handle;
113 char *file; 113 char *file;
114 char *name; 114 char *name;
@@ -135,7 +135,7 @@ struct plugin_option {
135 * PEVENT_PLUGIN_OPTIONS: (optional) 135 * PEVENT_PLUGIN_OPTIONS: (optional)
136 * Plugin options that can be set before loading 136 * Plugin options that can be set before loading
137 * 137 *
138 * struct plugin_option PEVENT_PLUGIN_OPTIONS[] = { 138 * struct pevent_plugin_option PEVENT_PLUGIN_OPTIONS[] = {
139 * { 139 * {
140 * .name = "option-name", 140 * .name = "option-name",
141 * .plugin_alias = "overide-file-name", (optional) 141 * .plugin_alias = "overide-file-name", (optional)
@@ -208,6 +208,11 @@ struct print_arg_string {
208 int offset; 208 int offset;
209}; 209};
210 210
211struct print_arg_bitmask {
212 char *bitmask;
213 int offset;
214};
215
211struct print_arg_field { 216struct print_arg_field {
212 char *name; 217 char *name;
213 struct format_field *field; 218 struct format_field *field;
@@ -274,6 +279,7 @@ enum print_arg_type {
274 PRINT_DYNAMIC_ARRAY, 279 PRINT_DYNAMIC_ARRAY,
275 PRINT_OP, 280 PRINT_OP,
276 PRINT_FUNC, 281 PRINT_FUNC,
282 PRINT_BITMASK,
277}; 283};
278 284
279struct print_arg { 285struct print_arg {
@@ -288,6 +294,7 @@ struct print_arg {
288 struct print_arg_hex hex; 294 struct print_arg_hex hex;
289 struct print_arg_func func; 295 struct print_arg_func func;
290 struct print_arg_string string; 296 struct print_arg_string string;
297 struct print_arg_bitmask bitmask;
291 struct print_arg_op op; 298 struct print_arg_op op;
292 struct print_arg_dynarray dynarray; 299 struct print_arg_dynarray dynarray;
293 }; 300 };
@@ -354,6 +361,8 @@ enum pevent_func_arg_type {
354 361
355enum pevent_flag { 362enum pevent_flag {
356 PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */ 363 PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */
364 PEVENT_DISABLE_SYS_PLUGINS = 1 << 1,
365 PEVENT_DISABLE_PLUGINS = 1 << 2,
357}; 366};
358 367
359#define PEVENT_ERRORS \ 368#define PEVENT_ERRORS \
@@ -410,9 +419,19 @@ enum pevent_errno {
410 419
411struct plugin_list; 420struct plugin_list;
412 421
422#define INVALID_PLUGIN_LIST_OPTION ((char **)((unsigned long)-1))
423
413struct plugin_list *traceevent_load_plugins(struct pevent *pevent); 424struct plugin_list *traceevent_load_plugins(struct pevent *pevent);
414void traceevent_unload_plugins(struct plugin_list *plugin_list, 425void traceevent_unload_plugins(struct plugin_list *plugin_list,
415 struct pevent *pevent); 426 struct pevent *pevent);
427char **traceevent_plugin_list_options(void);
428void traceevent_plugin_free_options_list(char **list);
429int traceevent_plugin_add_options(const char *name,
430 struct pevent_plugin_option *options);
431void traceevent_plugin_remove_options(struct pevent_plugin_option *options);
432void traceevent_print_plugins(struct trace_seq *s,
433 const char *prefix, const char *suffix,
434 const struct plugin_list *list);
416 435
417struct cmdline; 436struct cmdline;
418struct cmdline_list; 437struct cmdline_list;
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c
index 0c8bf6780e4d..136162c03af1 100644
--- a/tools/lib/traceevent/event-plugin.c
+++ b/tools/lib/traceevent/event-plugin.c
@@ -18,6 +18,7 @@
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */ 19 */
20 20
21#include <stdio.h>
21#include <string.h> 22#include <string.h>
22#include <dlfcn.h> 23#include <dlfcn.h>
23#include <stdlib.h> 24#include <stdlib.h>
@@ -30,12 +31,207 @@
30 31
31#define LOCAL_PLUGIN_DIR ".traceevent/plugins" 32#define LOCAL_PLUGIN_DIR ".traceevent/plugins"
32 33
34static struct registered_plugin_options {
35 struct registered_plugin_options *next;
36 struct pevent_plugin_option *options;
37} *registered_options;
38
39static struct trace_plugin_options {
40 struct trace_plugin_options *next;
41 char *plugin;
42 char *option;
43 char *value;
44} *trace_plugin_options;
45
33struct plugin_list { 46struct plugin_list {
34 struct plugin_list *next; 47 struct plugin_list *next;
35 char *name; 48 char *name;
36 void *handle; 49 void *handle;
37}; 50};
38 51
52/**
53 * traceevent_plugin_list_options - get list of plugin options
54 *
55 * Returns an array of char strings that list the currently registered
56 * plugin options in the format of <plugin>:<option>. This list can be
57 * used by toggling the option.
58 *
59 * Returns NULL if there's no options registered. On error it returns
60 * INVALID_PLUGIN_LIST_OPTION
61 *
62 * Must be freed with traceevent_plugin_free_options_list().
63 */
64char **traceevent_plugin_list_options(void)
65{
66 struct registered_plugin_options *reg;
67 struct pevent_plugin_option *op;
68 char **list = NULL;
69 char *name;
70 int count = 0;
71
72 for (reg = registered_options; reg; reg = reg->next) {
73 for (op = reg->options; op->name; op++) {
74 char *alias = op->plugin_alias ? op->plugin_alias : op->file;
75 char **temp = list;
76
77 name = malloc(strlen(op->name) + strlen(alias) + 2);
78 if (!name)
79 goto err;
80
81 sprintf(name, "%s:%s", alias, op->name);
82 list = realloc(list, count + 2);
83 if (!list) {
84 list = temp;
85 free(name);
86 goto err;
87 }
88 list[count++] = name;
89 list[count] = NULL;
90 }
91 }
92 return list;
93
94 err:
95 while (--count >= 0)
96 free(list[count]);
97 free(list);
98
99 return INVALID_PLUGIN_LIST_OPTION;
100}
101
102void traceevent_plugin_free_options_list(char **list)
103{
104 int i;
105
106 if (!list)
107 return;
108
109 if (list == INVALID_PLUGIN_LIST_OPTION)
110 return;
111
112 for (i = 0; list[i]; i++)
113 free(list[i]);
114
115 free(list);
116}
117
118static int
119update_option(const char *file, struct pevent_plugin_option *option)
120{
121 struct trace_plugin_options *op;
122 char *plugin;
123
124 if (option->plugin_alias) {
125 plugin = strdup(option->plugin_alias);
126 if (!plugin)
127 return -1;
128 } else {
129 char *p;
130 plugin = strdup(file);
131 if (!plugin)
132 return -1;
133 p = strstr(plugin, ".");
134 if (p)
135 *p = '\0';
136 }
137
138 /* first look for named options */
139 for (op = trace_plugin_options; op; op = op->next) {
140 if (!op->plugin)
141 continue;
142 if (strcmp(op->plugin, plugin) != 0)
143 continue;
144 if (strcmp(op->option, option->name) != 0)
145 continue;
146
147 option->value = op->value;
148 option->set ^= 1;
149 goto out;
150 }
151
152 /* first look for unnamed options */
153 for (op = trace_plugin_options; op; op = op->next) {
154 if (op->plugin)
155 continue;
156 if (strcmp(op->option, option->name) != 0)
157 continue;
158
159 option->value = op->value;
160 option->set ^= 1;
161 break;
162 }
163
164 out:
165 free(plugin);
166 return 0;
167}
168
169/**
170 * traceevent_plugin_add_options - Add a set of options by a plugin
171 * @name: The name of the plugin adding the options
172 * @options: The set of options being loaded
173 *
174 * Sets the options with the values that have been added by user.
175 */
176int traceevent_plugin_add_options(const char *name,
177 struct pevent_plugin_option *options)
178{
179 struct registered_plugin_options *reg;
180
181 reg = malloc(sizeof(*reg));
182 if (!reg)
183 return -1;
184 reg->next = registered_options;
185 reg->options = options;
186 registered_options = reg;
187
188 while (options->name) {
189 update_option(name, options);
190 options++;
191 }
192 return 0;
193}
194
195/**
196 * traceevent_plugin_remove_options - remove plugin options that were registered
197 * @options: Options to removed that were registered with traceevent_plugin_add_options
198 */
199void traceevent_plugin_remove_options(struct pevent_plugin_option *options)
200{
201 struct registered_plugin_options **last;
202 struct registered_plugin_options *reg;
203
204 for (last = &registered_options; *last; last = &(*last)->next) {
205 if ((*last)->options == options) {
206 reg = *last;
207 *last = reg->next;
208 free(reg);
209 return;
210 }
211 }
212}
213
214/**
215 * traceevent_print_plugins - print out the list of plugins loaded
216 * @s: the trace_seq descripter to write to
217 * @prefix: The prefix string to add before listing the option name
218 * @suffix: The suffix string ot append after the option name
219 * @list: The list of plugins (usually returned by traceevent_load_plugins()
220 *
221 * Writes to the trace_seq @s the list of plugins (files) that is
222 * returned by traceevent_load_plugins(). Use @prefix and @suffix for formating:
223 * @prefix = " ", @suffix = "\n".
224 */
225void traceevent_print_plugins(struct trace_seq *s,
226 const char *prefix, const char *suffix,
227 const struct plugin_list *list)
228{
229 while (list) {
230 trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
231 list = list->next;
232 }
233}
234
39static void 235static void
40load_plugin(struct pevent *pevent, const char *path, 236load_plugin(struct pevent *pevent, const char *path,
41 const char *file, void *data) 237 const char *file, void *data)
@@ -148,12 +344,17 @@ load_plugins(struct pevent *pevent, const char *suffix,
148 char *path; 344 char *path;
149 char *envdir; 345 char *envdir;
150 346
347 if (pevent->flags & PEVENT_DISABLE_PLUGINS)
348 return;
349
151 /* 350 /*
152 * If a system plugin directory was defined, 351 * If a system plugin directory was defined,
153 * check that first. 352 * check that first.
154 */ 353 */
155#ifdef PLUGIN_DIR 354#ifdef PLUGIN_DIR
156 load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data); 355 if (!(pevent->flags & PEVENT_DISABLE_SYS_PLUGINS))
356 load_plugins_dir(pevent, suffix, PLUGIN_DIR,
357 load_plugin, data);
157#endif 358#endif
158 359
159 /* 360 /*
diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c
index 80ba4ff1fe84..a00ec190821a 100644
--- a/tools/lib/traceevent/plugin_function.c
+++ b/tools/lib/traceevent/plugin_function.c
@@ -33,6 +33,29 @@ static int cpus = -1;
33 33
34#define STK_BLK 10 34#define STK_BLK 10
35 35
36struct pevent_plugin_option plugin_options[] =
37{
38 {
39 .name = "parent",
40 .plugin_alias = "ftrace",
41 .description =
42 "Print parent of functions for function events",
43 },
44 {
45 .name = "indent",
46 .plugin_alias = "ftrace",
47 .description =
48 "Try to show function call indents, based on parents",
49 .set = 1,
50 },
51 {
52 .name = NULL,
53 }
54};
55
56static struct pevent_plugin_option *ftrace_parent = &plugin_options[0];
57static struct pevent_plugin_option *ftrace_indent = &plugin_options[1];
58
36static void add_child(struct func_stack *stack, const char *child, int pos) 59static void add_child(struct func_stack *stack, const char *child, int pos)
37{ 60{
38 int i; 61 int i;
@@ -119,7 +142,8 @@ static int function_handler(struct trace_seq *s, struct pevent_record *record,
119 142
120 parent = pevent_find_function(pevent, pfunction); 143 parent = pevent_find_function(pevent, pfunction);
121 144
122 index = add_and_get_index(parent, func, record->cpu); 145 if (parent && ftrace_indent->set)
146 index = add_and_get_index(parent, func, record->cpu);
123 147
124 trace_seq_printf(s, "%*s", index*3, ""); 148 trace_seq_printf(s, "%*s", index*3, "");
125 149
@@ -128,11 +152,13 @@ static int function_handler(struct trace_seq *s, struct pevent_record *record,
128 else 152 else
129 trace_seq_printf(s, "0x%llx", function); 153 trace_seq_printf(s, "0x%llx", function);
130 154
131 trace_seq_printf(s, " <-- "); 155 if (ftrace_parent->set) {
132 if (parent) 156 trace_seq_printf(s, " <-- ");
133 trace_seq_printf(s, "%s", parent); 157 if (parent)
134 else 158 trace_seq_printf(s, "%s", parent);
135 trace_seq_printf(s, "0x%llx", pfunction); 159 else
160 trace_seq_printf(s, "0x%llx", pfunction);
161 }
136 162
137 return 0; 163 return 0;
138} 164}
@@ -141,6 +167,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
141{ 167{
142 pevent_register_event_handler(pevent, -1, "ftrace", "function", 168 pevent_register_event_handler(pevent, -1, "ftrace", "function",
143 function_handler, NULL); 169 function_handler, NULL);
170
171 traceevent_plugin_add_options("ftrace", plugin_options);
172
144 return 0; 173 return 0;
145} 174}
146 175
@@ -157,6 +186,8 @@ void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
157 free(fstack[i].stack); 186 free(fstack[i].stack);
158 } 187 }
159 188
189 traceevent_plugin_remove_options(plugin_options);
190
160 free(fstack); 191 free(fstack);
161 fstack = NULL; 192 fstack = NULL;
162 cpus = -1; 193 cpus = -1;