tracing/events: convert event call sites to use a link list
[linux-2.6] / kernel / trace / trace_events_filter.c
1 /*
2  * trace_events_filter - generic event filtering
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
19  */
20
21 #include <linux/debugfs.h>
22 #include <linux/uaccess.h>
23 #include <linux/module.h>
24 #include <linux/ctype.h>
25
26 #include "trace.h"
27 #include "trace_output.h"
28
29 static int filter_pred_64(struct filter_pred *pred, void *event)
30 {
31         u64 *addr = (u64 *)(event + pred->offset);
32         u64 val = (u64)pred->val;
33         int match;
34
35         match = (val == *addr) ^ pred->not;
36
37         return match;
38 }
39
40 static int filter_pred_32(struct filter_pred *pred, void *event)
41 {
42         u32 *addr = (u32 *)(event + pred->offset);
43         u32 val = (u32)pred->val;
44         int match;
45
46         match = (val == *addr) ^ pred->not;
47
48         return match;
49 }
50
51 static int filter_pred_16(struct filter_pred *pred, void *event)
52 {
53         u16 *addr = (u16 *)(event + pred->offset);
54         u16 val = (u16)pred->val;
55         int match;
56
57         match = (val == *addr) ^ pred->not;
58
59         return match;
60 }
61
62 static int filter_pred_8(struct filter_pred *pred, void *event)
63 {
64         u8 *addr = (u8 *)(event + pred->offset);
65         u8 val = (u8)pred->val;
66         int match;
67
68         match = (val == *addr) ^ pred->not;
69
70         return match;
71 }
72
73 static int filter_pred_string(struct filter_pred *pred, void *event)
74 {
75         char *addr = (char *)(event + pred->offset);
76         int cmp, match;
77
78         cmp = strncmp(addr, pred->str_val, pred->str_len);
79
80         match = (!cmp) ^ pred->not;
81
82         return match;
83 }
84
85 static int filter_pred_none(struct filter_pred *pred, void *event)
86 {
87         return 0;
88 }
89
90 /* return 1 if event matches, 0 otherwise (discard) */
91 int filter_match_preds(struct ftrace_event_call *call, void *rec)
92 {
93         int i, matched, and_failed = 0;
94         struct filter_pred *pred;
95
96         for (i = 0; i < call->n_preds; i++) {
97                 pred = call->preds[i];
98                 if (and_failed && !pred->or)
99                         continue;
100                 matched = pred->fn(pred, rec);
101                 if (!matched && !pred->or) {
102                         and_failed = 1;
103                         continue;
104                 } else if (matched && pred->or)
105                         return 1;
106         }
107
108         if (and_failed)
109                 return 0;
110
111         return 1;
112 }
113
114 void filter_print_preds(struct filter_pred **preds, int n_preds,
115                         struct trace_seq *s)
116 {
117         char *field_name;
118         struct filter_pred *pred;
119         int i;
120
121         if (!n_preds) {
122                 trace_seq_printf(s, "none\n");
123                 return;
124         }
125
126         for (i = 0; i < n_preds; i++) {
127                 pred = preds[i];
128                 field_name = pred->field_name;
129                 if (i)
130                         trace_seq_printf(s, pred->or ? "|| " : "&& ");
131                 trace_seq_printf(s, "%s ", field_name);
132                 trace_seq_printf(s, pred->not ? "!= " : "== ");
133                 if (pred->str_len)
134                         trace_seq_printf(s, "%s\n", pred->str_val);
135                 else
136                         trace_seq_printf(s, "%llu\n", pred->val);
137         }
138 }
139
140 static struct ftrace_event_field *
141 find_event_field(struct ftrace_event_call *call, char *name)
142 {
143         struct ftrace_event_field *field;
144
145         list_for_each_entry(field, &call->fields, link) {
146                 if (!strcmp(field->name, name))
147                         return field;
148         }
149
150         return NULL;
151 }
152
153 void filter_free_pred(struct filter_pred *pred)
154 {
155         if (!pred)
156                 return;
157
158         kfree(pred->field_name);
159         kfree(pred);
160 }
161
162 static void filter_clear_pred(struct filter_pred *pred)
163 {
164         kfree(pred->field_name);
165         pred->field_name = NULL;
166         pred->str_len = 0;
167 }
168
169 static int filter_set_pred(struct filter_pred *dest,
170                            struct filter_pred *src,
171                            filter_pred_fn_t fn)
172 {
173         *dest = *src;
174         dest->field_name = kstrdup(src->field_name, GFP_KERNEL);
175         if (!dest->field_name)
176                 return -ENOMEM;
177         dest->fn = fn;
178
179         return 0;
180 }
181
182 void filter_disable_preds(struct ftrace_event_call *call)
183 {
184         int i;
185
186         call->n_preds = 0;
187
188         for (i = 0; i < MAX_FILTER_PRED; i++)
189                 call->preds[i]->fn = filter_pred_none;
190 }
191
192 int init_preds(struct ftrace_event_call *call)
193 {
194         struct filter_pred *pred;
195         int i;
196
197         call->n_preds = 0;
198
199         call->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL);
200         if (!call->preds)
201                 return -ENOMEM;
202
203         for (i = 0; i < MAX_FILTER_PRED; i++) {
204                 pred = kzalloc(sizeof(*pred), GFP_KERNEL);
205                 if (!pred)
206                         goto oom;
207                 pred->fn = filter_pred_none;
208                 call->preds[i] = pred;
209         }
210
211         return 0;
212
213 oom:
214         for (i = 0; i < MAX_FILTER_PRED; i++) {
215                 if (call->preds[i])
216                         filter_free_pred(call->preds[i]);
217         }
218         kfree(call->preds);
219         call->preds = NULL;
220
221         return -ENOMEM;
222 }
223
224 void filter_free_subsystem_preds(struct event_subsystem *system)
225 {
226         struct ftrace_event_call *call;
227         int i;
228
229         if (system->n_preds) {
230                 for (i = 0; i < system->n_preds; i++)
231                         filter_free_pred(system->preds[i]);
232                 kfree(system->preds);
233                 system->preds = NULL;
234                 system->n_preds = 0;
235         }
236
237         list_for_each_entry(call, &ftrace_events, list) {
238                 if (!call->define_fields)
239                         continue;
240
241                 if (!strcmp(call->system, system->name))
242                         filter_disable_preds(call);
243         }
244 }
245
246 static int __filter_add_pred(struct ftrace_event_call *call,
247                              struct filter_pred *pred,
248                              filter_pred_fn_t fn)
249 {
250         int idx, err;
251
252         if (call->n_preds && !pred->compound)
253                 filter_disable_preds(call);
254
255         if (call->n_preds == MAX_FILTER_PRED)
256                 return -ENOSPC;
257
258         idx = call->n_preds;
259         filter_clear_pred(call->preds[idx]);
260         err = filter_set_pred(call->preds[idx], pred, fn);
261         if (err)
262                 return err;
263
264         call->n_preds++;
265
266         return 0;
267 }
268
269 static int is_string_field(const char *type)
270 {
271         if (strchr(type, '[') && strstr(type, "char"))
272                 return 1;
273
274         return 0;
275 }
276
277 int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
278 {
279         struct ftrace_event_field *field;
280         filter_pred_fn_t fn;
281
282         field = find_event_field(call, pred->field_name);
283         if (!field)
284                 return -EINVAL;
285
286         pred->fn = filter_pred_none;
287         pred->offset = field->offset;
288
289         if (is_string_field(field->type)) {
290                 if (!pred->str_len)
291                         return -EINVAL;
292                 fn = filter_pred_string;
293                 pred->str_len = field->size;
294                 return __filter_add_pred(call, pred, fn);
295         } else {
296                 if (pred->str_len)
297                         return -EINVAL;
298         }
299
300         switch (field->size) {
301         case 8:
302                 fn = filter_pred_64;
303                 break;
304         case 4:
305                 fn = filter_pred_32;
306                 break;
307         case 2:
308                 fn = filter_pred_16;
309                 break;
310         case 1:
311                 fn = filter_pred_8;
312                 break;
313         default:
314                 return -EINVAL;
315         }
316
317         return __filter_add_pred(call, pred, fn);
318 }
319
320 int filter_add_subsystem_pred(struct event_subsystem *system,
321                               struct filter_pred *pred)
322 {
323         struct ftrace_event_call *call;
324
325         if (system->n_preds && !pred->compound)
326                 filter_free_subsystem_preds(system);
327
328         if (!system->n_preds) {
329                 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
330                                         GFP_KERNEL);
331                 if (!system->preds)
332                         return -ENOMEM;
333         }
334
335         if (system->n_preds == MAX_FILTER_PRED)
336                 return -ENOSPC;
337
338         system->preds[system->n_preds] = pred;
339
340         list_for_each_entry(call, &ftrace_events, list) {
341                 int err;
342
343                 if (!call->define_fields)
344                         continue;
345
346                 if (strcmp(call->system, system->name))
347                         continue;
348
349                 if (!find_event_field(call, pred->field_name))
350                         continue;
351
352                 err = filter_add_pred(call, pred);
353                 if (err == -ENOMEM) {
354                         system->preds[system->n_preds] = NULL;
355                         return err;
356                 }
357         }
358
359         system->n_preds++;
360
361         return 0;
362 }
363
364 int filter_parse(char **pbuf, struct filter_pred *pred)
365 {
366         char *tmp, *tok, *val_str = NULL;
367         int tok_n = 0;
368
369         /* field ==/!= number, or/and field ==/!= number, number */
370         while ((tok = strsep(pbuf, " \n"))) {
371                 if (tok_n == 0) {
372                         if (!strcmp(tok, "0")) {
373                                 pred->clear = 1;
374                                 return 0;
375                         } else if (!strcmp(tok, "&&")) {
376                                 pred->or = 0;
377                                 pred->compound = 1;
378                         } else if (!strcmp(tok, "||")) {
379                                 pred->or = 1;
380                                 pred->compound = 1;
381                         } else
382                                 pred->field_name = tok;
383                         tok_n = 1;
384                         continue;
385                 }
386                 if (tok_n == 1) {
387                         if (!pred->field_name)
388                                 pred->field_name = tok;
389                         else if (!strcmp(tok, "!="))
390                                 pred->not = 1;
391                         else if (!strcmp(tok, "=="))
392                                 pred->not = 0;
393                         else {
394                                 pred->field_name = NULL;
395                                 return -EINVAL;
396                         }
397                         tok_n = 2;
398                         continue;
399                 }
400                 if (tok_n == 2) {
401                         if (pred->compound) {
402                                 if (!strcmp(tok, "!="))
403                                         pred->not = 1;
404                                 else if (!strcmp(tok, "=="))
405                                         pred->not = 0;
406                                 else {
407                                         pred->field_name = NULL;
408                                         return -EINVAL;
409                                 }
410                         } else {
411                                 val_str = tok;
412                                 break; /* done */
413                         }
414                         tok_n = 3;
415                         continue;
416                 }
417                 if (tok_n == 3) {
418                         val_str = tok;
419                         break; /* done */
420                 }
421         }
422
423         if (!val_str || !strlen(val_str)
424             || strlen(val_str) >= MAX_FILTER_STR_VAL) {
425                 pred->field_name = NULL;
426                 return -EINVAL;
427         }
428
429         pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
430         if (!pred->field_name)
431                 return -ENOMEM;
432
433         pred->str_len = 0;
434         pred->val = simple_strtoull(val_str, &tmp, 0);
435         if (tmp == val_str) {
436                 strncpy(pred->str_val, val_str, MAX_FILTER_STR_VAL);
437                 pred->str_len = strlen(val_str);
438                 pred->str_val[pred->str_len] = '\0';
439         } else if (*tmp != '\0')
440                 return -EINVAL;
441
442         return 0;
443 }
444
445