tracing/events: fix compile for modules disabled
[safe/jmp/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 EXPORT_SYMBOL_GPL(filter_match_preds);
114
115 void filter_print_preds(struct filter_pred **preds, int n_preds,
116                         struct trace_seq *s)
117 {
118         char *field_name;
119         struct filter_pred *pred;
120         int i;
121
122         if (!n_preds) {
123                 trace_seq_printf(s, "none\n");
124                 return;
125         }
126
127         for (i = 0; i < n_preds; i++) {
128                 pred = preds[i];
129                 field_name = pred->field_name;
130                 if (i)
131                         trace_seq_printf(s, pred->or ? "|| " : "&& ");
132                 trace_seq_printf(s, "%s ", field_name);
133                 trace_seq_printf(s, pred->not ? "!= " : "== ");
134                 if (pred->str_len)
135                         trace_seq_printf(s, "%s\n", pred->str_val);
136                 else
137                         trace_seq_printf(s, "%llu\n", pred->val);
138         }
139 }
140
141 static struct ftrace_event_field *
142 find_event_field(struct ftrace_event_call *call, char *name)
143 {
144         struct ftrace_event_field *field;
145
146         list_for_each_entry(field, &call->fields, link) {
147                 if (!strcmp(field->name, name))
148                         return field;
149         }
150
151         return NULL;
152 }
153
154 void filter_free_pred(struct filter_pred *pred)
155 {
156         if (!pred)
157                 return;
158
159         kfree(pred->field_name);
160         kfree(pred);
161 }
162
163 static void filter_clear_pred(struct filter_pred *pred)
164 {
165         kfree(pred->field_name);
166         pred->field_name = NULL;
167         pred->str_len = 0;
168 }
169
170 static int filter_set_pred(struct filter_pred *dest,
171                            struct filter_pred *src,
172                            filter_pred_fn_t fn)
173 {
174         *dest = *src;
175         dest->field_name = kstrdup(src->field_name, GFP_KERNEL);
176         if (!dest->field_name)
177                 return -ENOMEM;
178         dest->fn = fn;
179
180         return 0;
181 }
182
183 void filter_disable_preds(struct ftrace_event_call *call)
184 {
185         int i;
186
187         call->n_preds = 0;
188
189         for (i = 0; i < MAX_FILTER_PRED; i++)
190                 call->preds[i]->fn = filter_pred_none;
191 }
192
193 int init_preds(struct ftrace_event_call *call)
194 {
195         struct filter_pred *pred;
196         int i;
197
198         call->n_preds = 0;
199
200         call->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL);
201         if (!call->preds)
202                 return -ENOMEM;
203
204         for (i = 0; i < MAX_FILTER_PRED; i++) {
205                 pred = kzalloc(sizeof(*pred), GFP_KERNEL);
206                 if (!pred)
207                         goto oom;
208                 pred->fn = filter_pred_none;
209                 call->preds[i] = pred;
210         }
211
212         return 0;
213
214 oom:
215         for (i = 0; i < MAX_FILTER_PRED; i++) {
216                 if (call->preds[i])
217                         filter_free_pred(call->preds[i]);
218         }
219         kfree(call->preds);
220         call->preds = NULL;
221
222         return -ENOMEM;
223 }
224 EXPORT_SYMBOL_GPL(init_preds);
225
226 void filter_free_subsystem_preds(struct event_subsystem *system)
227 {
228         struct ftrace_event_call *call;
229         int i;
230
231         if (system->n_preds) {
232                 for (i = 0; i < system->n_preds; i++)
233                         filter_free_pred(system->preds[i]);
234                 kfree(system->preds);
235                 system->preds = NULL;
236                 system->n_preds = 0;
237         }
238
239         list_for_each_entry(call, &ftrace_events, list) {
240                 if (!call->define_fields)
241                         continue;
242
243                 if (!strcmp(call->system, system->name))
244                         filter_disable_preds(call);
245         }
246 }
247
248 static int __filter_add_pred(struct ftrace_event_call *call,
249                              struct filter_pred *pred,
250                              filter_pred_fn_t fn)
251 {
252         int idx, err;
253
254         if (call->n_preds && !pred->compound)
255                 filter_disable_preds(call);
256
257         if (call->n_preds == MAX_FILTER_PRED)
258                 return -ENOSPC;
259
260         idx = call->n_preds;
261         filter_clear_pred(call->preds[idx]);
262         err = filter_set_pred(call->preds[idx], pred, fn);
263         if (err)
264                 return err;
265
266         call->n_preds++;
267
268         return 0;
269 }
270
271 static int is_string_field(const char *type)
272 {
273         if (strchr(type, '[') && strstr(type, "char"))
274                 return 1;
275
276         return 0;
277 }
278
279 int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
280 {
281         struct ftrace_event_field *field;
282         filter_pred_fn_t fn;
283
284         field = find_event_field(call, pred->field_name);
285         if (!field)
286                 return -EINVAL;
287
288         pred->fn = filter_pred_none;
289         pred->offset = field->offset;
290
291         if (is_string_field(field->type)) {
292                 if (!pred->str_len)
293                         return -EINVAL;
294                 fn = filter_pred_string;
295                 pred->str_len = field->size;
296                 return __filter_add_pred(call, pred, fn);
297         } else {
298                 if (pred->str_len)
299                         return -EINVAL;
300         }
301
302         switch (field->size) {
303         case 8:
304                 fn = filter_pred_64;
305                 break;
306         case 4:
307                 fn = filter_pred_32;
308                 break;
309         case 2:
310                 fn = filter_pred_16;
311                 break;
312         case 1:
313                 fn = filter_pred_8;
314                 break;
315         default:
316                 return -EINVAL;
317         }
318
319         return __filter_add_pred(call, pred, fn);
320 }
321
322 int filter_add_subsystem_pred(struct event_subsystem *system,
323                               struct filter_pred *pred)
324 {
325         struct ftrace_event_call *call;
326
327         if (system->n_preds && !pred->compound)
328                 filter_free_subsystem_preds(system);
329
330         if (!system->n_preds) {
331                 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
332                                         GFP_KERNEL);
333                 if (!system->preds)
334                         return -ENOMEM;
335         }
336
337         if (system->n_preds == MAX_FILTER_PRED)
338                 return -ENOSPC;
339
340         system->preds[system->n_preds] = pred;
341
342         list_for_each_entry(call, &ftrace_events, list) {
343                 int err;
344
345                 if (!call->define_fields)
346                         continue;
347
348                 if (strcmp(call->system, system->name))
349                         continue;
350
351                 if (!find_event_field(call, pred->field_name))
352                         continue;
353
354                 err = filter_add_pred(call, pred);
355                 if (err == -ENOMEM) {
356                         system->preds[system->n_preds] = NULL;
357                         return err;
358                 }
359         }
360
361         system->n_preds++;
362
363         return 0;
364 }
365
366 int filter_parse(char **pbuf, struct filter_pred *pred)
367 {
368         char *tmp, *tok, *val_str = NULL;
369         int tok_n = 0;
370
371         /* field ==/!= number, or/and field ==/!= number, number */
372         while ((tok = strsep(pbuf, " \n"))) {
373                 if (tok_n == 0) {
374                         if (!strcmp(tok, "0")) {
375                                 pred->clear = 1;
376                                 return 0;
377                         } else if (!strcmp(tok, "&&")) {
378                                 pred->or = 0;
379                                 pred->compound = 1;
380                         } else if (!strcmp(tok, "||")) {
381                                 pred->or = 1;
382                                 pred->compound = 1;
383                         } else
384                                 pred->field_name = tok;
385                         tok_n = 1;
386                         continue;
387                 }
388                 if (tok_n == 1) {
389                         if (!pred->field_name)
390                                 pred->field_name = tok;
391                         else if (!strcmp(tok, "!="))
392                                 pred->not = 1;
393                         else if (!strcmp(tok, "=="))
394                                 pred->not = 0;
395                         else {
396                                 pred->field_name = NULL;
397                                 return -EINVAL;
398                         }
399                         tok_n = 2;
400                         continue;
401                 }
402                 if (tok_n == 2) {
403                         if (pred->compound) {
404                                 if (!strcmp(tok, "!="))
405                                         pred->not = 1;
406                                 else if (!strcmp(tok, "=="))
407                                         pred->not = 0;
408                                 else {
409                                         pred->field_name = NULL;
410                                         return -EINVAL;
411                                 }
412                         } else {
413                                 val_str = tok;
414                                 break; /* done */
415                         }
416                         tok_n = 3;
417                         continue;
418                 }
419                 if (tok_n == 3) {
420                         val_str = tok;
421                         break; /* done */
422                 }
423         }
424
425         if (!val_str || !strlen(val_str)
426             || strlen(val_str) >= MAX_FILTER_STR_VAL) {
427                 pred->field_name = NULL;
428                 return -EINVAL;
429         }
430
431         pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
432         if (!pred->field_name)
433                 return -ENOMEM;
434
435         pred->str_len = 0;
436         pred->val = simple_strtoull(val_str, &tmp, 0);
437         if (tmp == val_str) {
438                 strncpy(pred->str_val, val_str, MAX_FILTER_STR_VAL);
439                 pred->str_len = strlen(val_str);
440                 pred->str_val[pred->str_len] = '\0';
441         } else if (*tmp != '\0')
442                 return -EINVAL;
443
444         return 0;
445 }
446
447