diff options
author | Steven Rostedt <srostedt@redhat.com> | 2010-03-23 09:49:40 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2010-03-23 09:49:40 -0400 |
commit | 7734efa436eb2a5fa86f079b9d8fa973b977e0dc (patch) | |
tree | bbe1ba87ffdb355536d204d3edc25641846921df | |
parent | d632824b6d9993a862a8c7b6b71745ea8ed24bee (diff) |
parse-events: Add hook for plugins to register function handling
Sometimes an event may use a helper function inside the print format.
Unfortunately, parse-events does not know how to handle these.
This patch adds a registration function pevent_register_print_function()
That a plugin can use to register how to handle helper functions
in the event's print format.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | parse-events.c | 265 | ||||
-rw-r--r-- | parse-events.h | 26 |
2 files changed, 285 insertions, 6 deletions
diff --git a/parse-events.c b/parse-events.c index aa4ea94..e942916 100644 --- a/parse-events.c +++ b/parse-events.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <stdio.h> | 28 | #include <stdio.h> |
29 | #include <stdlib.h> | 29 | #include <stdlib.h> |
30 | #include <string.h> | 30 | #include <string.h> |
31 | #include <stdarg.h> | ||
31 | #include <ctype.h> | 32 | #include <ctype.h> |
32 | #include <errno.h> | 33 | #include <errno.h> |
33 | 34 | ||
@@ -60,6 +61,24 @@ struct event_handler { | |||
60 | pevent_event_handler_func func; | 61 | pevent_event_handler_func func; |
61 | }; | 62 | }; |
62 | 63 | ||
64 | struct pevent_func_params { | ||
65 | struct pevent_func_params *next; | ||
66 | enum pevent_func_arg_type type; | ||
67 | }; | ||
68 | |||
69 | struct pevent_function_handler { | ||
70 | struct pevent_function_handler *next; | ||
71 | enum pevent_func_arg_type ret_type; | ||
72 | char *name; | ||
73 | pevent_func_handler func; | ||
74 | struct pevent_func_params *params; | ||
75 | int nr_args; | ||
76 | }; | ||
77 | |||
78 | static unsigned long long | ||
79 | process_defined_func(struct trace_seq *s, void *data, int size, | ||
80 | struct event_format *event, struct print_arg *arg); | ||
81 | |||
63 | /** | 82 | /** |
64 | * pevent_buffer_init - init buffer for parsing | 83 | * pevent_buffer_init - init buffer for parsing |
65 | * @buf: buffer to parse | 84 | * @buf: buffer to parse |
@@ -634,6 +653,8 @@ static void free_flag_sym(struct print_flag_sym *fsym) | |||
634 | 653 | ||
635 | static void free_arg(struct print_arg *arg) | 654 | static void free_arg(struct print_arg *arg) |
636 | { | 655 | { |
656 | struct print_arg *farg; | ||
657 | |||
637 | if (!arg) | 658 | if (!arg) |
638 | return; | 659 | return; |
639 | 660 | ||
@@ -667,6 +688,14 @@ static void free_arg(struct print_arg *arg) | |||
667 | free(arg->op.op); | 688 | free(arg->op.op); |
668 | free_arg(arg->op.left); | 689 | free_arg(arg->op.left); |
669 | free_arg(arg->op.right); | 690 | free_arg(arg->op.right); |
691 | break; | ||
692 | case PRINT_FUNC: | ||
693 | while (arg->func.args) { | ||
694 | farg = arg->func.args; | ||
695 | arg->func.args = farg->next; | ||
696 | free_arg(farg); | ||
697 | } | ||
698 | break; | ||
670 | 699 | ||
671 | case PRINT_NULL: | 700 | case PRINT_NULL: |
672 | default: | 701 | default: |
@@ -2201,10 +2230,66 @@ process_str(struct event_format *event __unused, struct print_arg *arg, char **t | |||
2201 | return EVENT_ERROR; | 2230 | return EVENT_ERROR; |
2202 | } | 2231 | } |
2203 | 2232 | ||
2233 | static struct pevent_function_handler * | ||
2234 | find_func_handler(struct pevent *pevent, char *func_name) | ||
2235 | { | ||
2236 | struct pevent_function_handler *func; | ||
2237 | |||
2238 | for (func = pevent->func_handlers; func; func = func->next) { | ||
2239 | if (strcmp(func->name, func_name) == 0) | ||
2240 | break; | ||
2241 | } | ||
2242 | |||
2243 | return func; | ||
2244 | } | ||
2245 | |||
2246 | static enum event_type | ||
2247 | process_func_handler(struct event_format *event, struct pevent_function_handler *func, | ||
2248 | struct print_arg *arg, char **tok) | ||
2249 | { | ||
2250 | struct print_arg **next_arg; | ||
2251 | struct print_arg *farg; | ||
2252 | enum event_type type; | ||
2253 | char *token; | ||
2254 | char *test; | ||
2255 | int i; | ||
2256 | |||
2257 | arg->type = PRINT_FUNC; | ||
2258 | arg->func.func = func; | ||
2259 | |||
2260 | *tok = NULL; | ||
2261 | |||
2262 | next_arg = &(arg->func.args); | ||
2263 | for (i = 0; i < func->nr_args; i++) { | ||
2264 | farg = alloc_arg(); | ||
2265 | type = process_arg(event, farg, &token); | ||
2266 | if (i < (func->nr_args - 1)) | ||
2267 | test = ","; | ||
2268 | else | ||
2269 | test = ")"; | ||
2270 | |||
2271 | if (test_type_token(type, token, EVENT_DELIM, test)) { | ||
2272 | free_arg(farg); | ||
2273 | free_token(token); | ||
2274 | return EVENT_ERROR; | ||
2275 | } | ||
2276 | |||
2277 | *next_arg = farg; | ||
2278 | next_arg = &(farg->next); | ||
2279 | } | ||
2280 | |||
2281 | type = read_token(&token); | ||
2282 | *tok = token; | ||
2283 | |||
2284 | return type; | ||
2285 | } | ||
2286 | |||
2204 | static enum event_type | 2287 | static enum event_type |
2205 | process_function(struct event_format *event, struct print_arg *arg, | 2288 | process_function(struct event_format *event, struct print_arg *arg, |
2206 | char *token, char **tok) | 2289 | char *token, char **tok) |
2207 | { | 2290 | { |
2291 | struct pevent_function_handler *func; | ||
2292 | |||
2208 | if (strcmp(token, "__print_flags") == 0) { | 2293 | if (strcmp(token, "__print_flags") == 0) { |
2209 | free_token(token); | 2294 | free_token(token); |
2210 | return process_flags(event, arg, tok); | 2295 | return process_flags(event, arg, tok); |
@@ -2222,6 +2307,12 @@ process_function(struct event_format *event, struct print_arg *arg, | |||
2222 | return process_dynamic_array(event, arg, tok); | 2307 | return process_dynamic_array(event, arg, tok); |
2223 | } | 2308 | } |
2224 | 2309 | ||
2310 | func = find_func_handler(event->pevent, token); | ||
2311 | if (func) { | ||
2312 | free_token(token); | ||
2313 | return process_func_handler(event, func, arg, tok); | ||
2314 | } | ||
2315 | |||
2225 | do_warning("function %s not defined", token); | 2316 | do_warning("function %s not defined", token); |
2226 | free_token(token); | 2317 | free_token(token); |
2227 | return EVENT_ERROR; | 2318 | return EVENT_ERROR; |
@@ -2717,7 +2808,11 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg | |||
2717 | return eval_type(val, arg, 0); | 2808 | return eval_type(val, arg, 0); |
2718 | case PRINT_STRING: | 2809 | case PRINT_STRING: |
2719 | return 0; | 2810 | return 0; |
2720 | break; | 2811 | case PRINT_FUNC: { |
2812 | struct trace_seq s; | ||
2813 | trace_seq_init(&s); | ||
2814 | return process_defined_func(&s, data, size, event, arg); | ||
2815 | } | ||
2721 | case PRINT_OP: | 2816 | case PRINT_OP: |
2722 | if (strcmp(arg->op.op, "[") == 0) { | 2817 | if (strcmp(arg->op.op, "[") == 0) { |
2723 | /* | 2818 | /* |
@@ -2974,12 +3069,81 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
2974 | else | 3069 | else |
2975 | print_str_arg(s, data, size, event, arg->op.right->op.right); | 3070 | print_str_arg(s, data, size, event, arg->op.right->op.right); |
2976 | break; | 3071 | break; |
3072 | case PRINT_FUNC: | ||
3073 | process_defined_func(s, data, size, event, arg); | ||
3074 | break; | ||
2977 | default: | 3075 | default: |
2978 | /* well... */ | 3076 | /* well... */ |
2979 | break; | 3077 | break; |
2980 | } | 3078 | } |
2981 | } | 3079 | } |
2982 | 3080 | ||
3081 | static unsigned long long | ||
3082 | process_defined_func(struct trace_seq *s, void *data, int size, | ||
3083 | struct event_format *event, struct print_arg *arg) | ||
3084 | { | ||
3085 | struct pevent_function_handler *func_handle = arg->func.func; | ||
3086 | struct pevent_func_params *param; | ||
3087 | unsigned long long *args; | ||
3088 | unsigned long long ret; | ||
3089 | struct print_arg *farg; | ||
3090 | struct trace_seq str; | ||
3091 | struct save_str { | ||
3092 | struct save_str *next; | ||
3093 | char *str; | ||
3094 | } *strings = NULL, *string; | ||
3095 | int i; | ||
3096 | |||
3097 | if (!func_handle->nr_args) { | ||
3098 | ret = (*func_handle->func)(s, NULL); | ||
3099 | goto out; | ||
3100 | } | ||
3101 | |||
3102 | farg = arg->func.args; | ||
3103 | param = func_handle->params; | ||
3104 | |||
3105 | args = malloc_or_die(sizeof(*args) * func_handle->nr_args); | ||
3106 | for (i = 0; i < func_handle->nr_args; i++) { | ||
3107 | switch (param->type) { | ||
3108 | case PEVENT_FUNC_ARG_INT: | ||
3109 | case PEVENT_FUNC_ARG_LONG: | ||
3110 | case PEVENT_FUNC_ARG_PTR: | ||
3111 | args[i] = eval_num_arg(data, size, event, farg); | ||
3112 | break; | ||
3113 | case PEVENT_FUNC_ARG_STRING: | ||
3114 | trace_seq_init(&str); | ||
3115 | print_str_arg(&str, data, size, event, farg); | ||
3116 | trace_seq_terminate(&str); | ||
3117 | string = malloc_or_die(sizeof(*string)); | ||
3118 | string->next = strings; | ||
3119 | string->str = strdup(str.buffer); | ||
3120 | strings = string; | ||
3121 | break; | ||
3122 | default: | ||
3123 | /* | ||
3124 | * Something went totally wrong, this is not | ||
3125 | * an input error, something in this code broke. | ||
3126 | */ | ||
3127 | die("Unexpected end of arguments\n"); | ||
3128 | break; | ||
3129 | } | ||
3130 | farg = farg->next; | ||
3131 | } | ||
3132 | |||
3133 | ret = (*func_handle->func)(s, args); | ||
3134 | free(args); | ||
3135 | while (strings) { | ||
3136 | string = strings; | ||
3137 | strings = string->next; | ||
3138 | free(string->str); | ||
3139 | free(string); | ||
3140 | } | ||
3141 | |||
3142 | out: | ||
3143 | /* TBD : handle return type here */ | ||
3144 | return ret; | ||
3145 | } | ||
3146 | |||
2983 | static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event_format *event) | 3147 | static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event_format *event) |
2984 | { | 3148 | { |
2985 | struct pevent *pevent = event->pevent; | 3149 | struct pevent *pevent = event->pevent; |
@@ -3143,12 +3307,17 @@ get_bprint_format(void *data, int size __unused, struct event_format *event) | |||
3143 | return format; | 3307 | return format; |
3144 | } | 3308 | } |
3145 | 3309 | ||
3146 | static void print_mac_arg(struct trace_seq *s, int mac, void *data, | 3310 | static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size, |
3147 | struct event_format *event, struct print_arg *arg) | 3311 | struct event_format *event, struct print_arg *arg) |
3148 | { | 3312 | { |
3149 | unsigned char *buf; | 3313 | unsigned char *buf; |
3150 | char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"; | 3314 | char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"; |
3151 | 3315 | ||
3316 | if (arg->type == PRINT_FUNC) { | ||
3317 | process_defined_func(s, data, size, event, arg); | ||
3318 | return; | ||
3319 | } | ||
3320 | |||
3152 | if (arg->type != PRINT_FIELD) { | 3321 | if (arg->type != PRINT_FIELD) { |
3153 | trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", | 3322 | trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d", |
3154 | arg->type); | 3323 | arg->type); |
@@ -3256,7 +3425,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event | |||
3256 | ptr++; | 3425 | ptr++; |
3257 | show_func = *ptr; | 3426 | show_func = *ptr; |
3258 | } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') { | 3427 | } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') { |
3259 | print_mac_arg(s, *(ptr+1), data, event, arg); | 3428 | print_mac_arg(s, *(ptr+1), data, size, event, arg); |
3260 | ptr++; | 3429 | ptr++; |
3261 | break; | 3430 | break; |
3262 | } | 3431 | } |
@@ -3972,6 +4141,8 @@ int pevent_parse_event(struct pevent *pevent, | |||
3972 | if (find_event_handle(pevent, event)) | 4141 | if (find_event_handle(pevent, event)) |
3973 | show_warning = 0; | 4142 | show_warning = 0; |
3974 | 4143 | ||
4144 | /* Add pevent to event so that function list can be referenced */ | ||
4145 | event->pevent = pevent; | ||
3975 | ret = event_read_print(event); | 4146 | ret = event_read_print(event); |
3976 | if (ret < 0) { | 4147 | if (ret < 0) { |
3977 | do_warning("failed to read event print fmt for %s", | 4148 | do_warning("failed to read event print fmt for %s", |
@@ -4014,6 +4185,94 @@ int pevent_parse_event(struct pevent *pevent, | |||
4014 | return -1; | 4185 | return -1; |
4015 | } | 4186 | } |
4016 | 4187 | ||
4188 | static void free_func_handle(struct pevent_function_handler *func) | ||
4189 | { | ||
4190 | struct pevent_func_params *params; | ||
4191 | |||
4192 | free(func->name); | ||
4193 | |||
4194 | while (func->params) { | ||
4195 | params = func->params; | ||
4196 | func->params = params->next; | ||
4197 | free(params); | ||
4198 | } | ||
4199 | |||
4200 | free(func); | ||
4201 | } | ||
4202 | |||
4203 | /** | ||
4204 | * pevent_register_print_function - register a helper function | ||
4205 | * @pevent: the handle to the pevent | ||
4206 | * @func: the function to process the helper function | ||
4207 | * @name: the name of the helper function | ||
4208 | * @parameters: A list of enum pevent_func_arg_type | ||
4209 | * | ||
4210 | * Some events may have helper functions in the print format arguments. | ||
4211 | * This allows a plugin to dynmically create a way to process one | ||
4212 | * of these functions. | ||
4213 | * | ||
4214 | * The @parameters is a variable list of pevent_func_arg_type enums that | ||
4215 | * must end with PEVENT_FUNC_ARG_VOID. | ||
4216 | */ | ||
4217 | int pevent_register_print_function(struct pevent *pevent, | ||
4218 | pevent_func_handler func, | ||
4219 | enum pevent_func_arg_type ret_type, | ||
4220 | char *name, ...) | ||
4221 | { | ||
4222 | struct pevent_function_handler *func_handle; | ||
4223 | struct pevent_func_params **next_param; | ||
4224 | struct pevent_func_params *param; | ||
4225 | enum pevent_func_arg_type type; | ||
4226 | va_list ap; | ||
4227 | |||
4228 | func_handle = find_func_handler(pevent, name); | ||
4229 | if (func_handle) { | ||
4230 | warning("function helper '%s' already defined", name); | ||
4231 | return -1; | ||
4232 | } | ||
4233 | |||
4234 | func_handle = malloc_or_die(sizeof(*func_handle)); | ||
4235 | memset(func_handle, 0, sizeof(*func_handle)); | ||
4236 | |||
4237 | func_handle->ret_type = ret_type; | ||
4238 | func_handle->name = strdup(name); | ||
4239 | func_handle->func = func; | ||
4240 | if (!func_handle->name) | ||
4241 | die("Failed to allocate function name"); | ||
4242 | |||
4243 | next_param = &(func_handle->params); | ||
4244 | va_start(ap, name); | ||
4245 | for (;;) { | ||
4246 | type = va_arg(ap, enum pevent_func_arg_type); | ||
4247 | if (type == PEVENT_FUNC_ARG_VOID) | ||
4248 | break; | ||
4249 | |||
4250 | if (type < 0 || type >= PEVENT_FUNC_ARG_MAX_TYPES) { | ||
4251 | warning("Invalid argument type %d", type); | ||
4252 | goto out_free; | ||
4253 | } | ||
4254 | |||
4255 | param = malloc_or_die(sizeof(*param)); | ||
4256 | param->type = type; | ||
4257 | param->next = NULL; | ||
4258 | |||
4259 | *next_param = param; | ||
4260 | next_param = &(param->next); | ||
4261 | |||
4262 | func_handle->nr_args++; | ||
4263 | } | ||
4264 | va_end(ap); | ||
4265 | |||
4266 | func_handle->next = pevent->func_handlers; | ||
4267 | pevent->func_handlers = func_handle; | ||
4268 | |||
4269 | return 0; | ||
4270 | out_free: | ||
4271 | va_end(ap); | ||
4272 | free_func_handle(func_handle); | ||
4273 | return -1; | ||
4274 | } | ||
4275 | |||
4017 | /** | 4276 | /** |
4018 | * pevent_register_event_handle - register a way to parse an event | 4277 | * pevent_register_event_handle - register a way to parse an event |
4019 | * @pevent: the handle to the pevent | 4278 | * @pevent: the handle to the pevent |
diff --git a/parse-events.h b/parse-events.h index d85aefd..33a5b70 100644 --- a/parse-events.h +++ b/parse-events.h | |||
@@ -176,9 +176,11 @@ struct print_arg_op { | |||
176 | struct print_arg *right; | 176 | struct print_arg *right; |
177 | }; | 177 | }; |
178 | 178 | ||
179 | struct pevent_function_handler; | ||
180 | |||
179 | struct print_arg_func { | 181 | struct print_arg_func { |
180 | char *name; | 182 | struct pevent_function_handler *func; |
181 | struct print_arg *args; | 183 | struct print_arg *args; |
182 | }; | 184 | }; |
183 | 185 | ||
184 | enum print_arg_type { | 186 | enum print_arg_type { |
@@ -191,6 +193,7 @@ enum print_arg_type { | |||
191 | PRINT_STRING, | 193 | PRINT_STRING, |
192 | PRINT_DYNAMIC_ARRAY, | 194 | PRINT_DYNAMIC_ARRAY, |
193 | PRINT_OP, | 195 | PRINT_OP, |
196 | PRINT_FUNC, | ||
194 | }; | 197 | }; |
195 | 198 | ||
196 | struct print_arg { | 199 | struct print_arg { |
@@ -253,6 +256,18 @@ enum event_type { | |||
253 | EVENT_SQUOTE, | 256 | EVENT_SQUOTE, |
254 | }; | 257 | }; |
255 | 258 | ||
259 | typedef unsigned long long (*pevent_func_handler)(struct trace_seq *s, | ||
260 | unsigned long long *args); | ||
261 | |||
262 | enum pevent_func_arg_type { | ||
263 | PEVENT_FUNC_ARG_VOID, | ||
264 | PEVENT_FUNC_ARG_INT, | ||
265 | PEVENT_FUNC_ARG_LONG, | ||
266 | PEVENT_FUNC_ARG_STRING, | ||
267 | PEVENT_FUNC_ARG_PTR, | ||
268 | PEVENT_FUNC_ARG_MAX_TYPES | ||
269 | }; | ||
270 | |||
256 | struct cmdline; | 271 | struct cmdline; |
257 | struct cmdline_list; | 272 | struct cmdline_list; |
258 | struct func_map; | 273 | struct func_map; |
@@ -316,6 +331,7 @@ struct pevent { | |||
316 | struct format_field *bprint_buf_field; | 331 | struct format_field *bprint_buf_field; |
317 | 332 | ||
318 | struct event_handler *handlers; | 333 | struct event_handler *handlers; |
334 | struct pevent_function_handler *func_handlers; | ||
319 | 335 | ||
320 | /* cache */ | 336 | /* cache */ |
321 | struct event_format *last_event; | 337 | struct event_format *last_event; |
@@ -390,7 +406,7 @@ enum trace_flag_type { | |||
390 | }; | 406 | }; |
391 | 407 | ||
392 | int pevent_register_comm(struct pevent *pevent, char *comm, int pid); | 408 | int pevent_register_comm(struct pevent *pevent, char *comm, int pid); |
393 | int pevent_register_function(struct pevent *pevetn, char *name, | 409 | int pevent_register_function(struct pevent *pevent, char *name, |
394 | unsigned long long addr, char *mod); | 410 | unsigned long long addr, char *mod); |
395 | int pevent_register_print_string(struct pevent *pevent, char *fmt, | 411 | int pevent_register_print_string(struct pevent *pevent, char *fmt, |
396 | unsigned long long addr); | 412 | unsigned long long addr); |
@@ -406,6 +422,10 @@ int pevent_parse_event(struct pevent *pevent, char *buf, unsigned long size, cha | |||
406 | 422 | ||
407 | int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name, | 423 | int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name, |
408 | pevent_event_handler_func func); | 424 | pevent_event_handler_func func); |
425 | int pevent_register_print_function(struct pevent *pevent, | ||
426 | pevent_func_handler func, | ||
427 | enum pevent_func_arg_type ret_type, | ||
428 | char *name, ...); | ||
409 | 429 | ||
410 | struct format_field *pevent_find_common_field(struct event_format *event, const char *name); | 430 | struct format_field *pevent_find_common_field(struct event_format *event, const char *name); |
411 | struct format_field *pevent_find_field(struct event_format *event, const char *name); | 431 | struct format_field *pevent_find_field(struct event_format *event, const char *name); |