tracing/events: make the filter files writable
[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
28 static int filter_pred_64(struct filter_pred *pred, void *event)
29 {
30         u64 *addr = (u64 *)(event + pred->offset);
31         u64 val = (u64)pred->val;
32         int match;
33
34         match = (val == *addr) ^ pred->not;
35
36         return match;
37 }
38
39 static int filter_pred_32(struct filter_pred *pred, void *event)
40 {
41         u32 *addr = (u32 *)(event + pred->offset);
42         u32 val = (u32)pred->val;
43         int match;
44
45         match = (val == *addr) ^ pred->not;
46
47         return match;
48 }
49
50 static int filter_pred_16(struct filter_pred *pred, void *event)
51 {
52         u16 *addr = (u16 *)(event + pred->offset);
53         u16 val = (u16)pred->val;
54         int match;
55
56         match = (val == *addr) ^ pred->not;
57
58         return match;
59 }
60
61 static int filter_pred_8(struct filter_pred *pred, void *event)
62 {
63         u8 *addr = (u8 *)(event + pred->offset);
64         u8 val = (u8)pred->val;
65         int match;
66
67         match = (val == *addr) ^ pred->not;
68
69         return match;
70 }
71
72 static int filter_pred_string(struct filter_pred *pred, void *event)
73 {
74         char *addr = (char *)(event + pred->offset);
75         int cmp, match;
76
77         cmp = strncmp(addr, pred->str_val, pred->str_len);
78
79         match = (!cmp) ^ pred->not;
80
81         return match;
82 }
83
84 /* return 1 if event matches, 0 otherwise (discard) */
85 int filter_match_preds(struct ftrace_event_call *call, void *rec)
86 {
87         int i, matched, and_failed = 0;
88         struct filter_pred *pred;
89
90         for (i = 0; i < MAX_FILTER_PRED; i++) {
91                 if (call->preds[i]) {
92                         pred = call->preds[i];
93                         if (and_failed && !pred->or)
94                                 continue;
95                         matched = pred->fn(pred, rec);
96                         if (!matched && !pred->or) {
97                                 and_failed = 1;
98                                 continue;
99                         } else if (matched && pred->or)
100                                 return 1;
101                 } else
102                         break;
103         }
104
105         if (and_failed)
106                 return 0;
107
108         return 1;
109 }
110
111 int filter_print_preds(struct filter_pred **preds, char *buf)
112 {
113         ssize_t this_len = 0;
114         char *field_name;
115         struct filter_pred *pred;
116         int i;
117
118         if (!preds) {
119                 this_len += sprintf(buf + this_len, "none\n");
120                 return this_len;
121         }
122
123         for (i = 0; i < MAX_FILTER_PRED; i++) {
124                 if (preds[i]) {
125                         pred = preds[i];
126                         field_name = pred->field_name;
127                         if (i)
128                                 this_len += sprintf(buf + this_len,
129                                             pred->or ? "|| " : "&& ");
130                         this_len += sprintf(buf + this_len,
131                                             "%s ", field_name);
132                         this_len += sprintf(buf + this_len,
133                                             pred->not ? "!= " : "== ");
134                         if (pred->str_val)
135                                 this_len += sprintf(buf + this_len,
136                                                     "%s\n", pred->str_val);
137                         else
138                                 this_len += sprintf(buf + this_len,
139                                                     "%llu\n", pred->val);
140                 } else
141                         break;
142         }
143
144         return this_len;
145 }
146
147 static struct ftrace_event_field *
148 find_event_field(struct ftrace_event_call *call, char *name)
149 {
150         struct ftrace_event_field *field;
151         struct list_head *entry, *tmp;
152
153         list_for_each_safe(entry, tmp, &call->fields) {
154                 field = list_entry(entry, struct ftrace_event_field, link);
155                 if (!strcmp(field->name, name))
156                         return field;
157         }
158
159         return NULL;
160 }
161
162 void filter_free_pred(struct filter_pred *pred)
163 {
164         if (!pred)
165                 return;
166
167         kfree(pred->field_name);
168         kfree(pred->str_val);
169         kfree(pred);
170 }
171
172 void filter_free_preds(struct ftrace_event_call *call)
173 {
174         int i;
175
176         if (call->preds) {
177                 for (i = 0; i < MAX_FILTER_PRED; i++)
178                         filter_free_pred(call->preds[i]);
179                 kfree(call->preds);
180                 call->preds = NULL;
181         }
182 }
183
184 void filter_free_subsystem_preds(struct event_subsystem *system)
185 {
186         struct ftrace_event_call *call = __start_ftrace_events;
187         int i;
188
189         if (system->preds) {
190                 for (i = 0; i < MAX_FILTER_PRED; i++)
191                         filter_free_pred(system->preds[i]);
192                 kfree(system->preds);
193                 system->preds = NULL;
194         }
195
196         events_for_each(call) {
197                 if (!call->name || !call->regfunc)
198                         continue;
199
200                 if (!strcmp(call->system, system->name))
201                         filter_free_preds(call);
202         }
203 }
204
205 static int __filter_add_pred(struct ftrace_event_call *call,
206                              struct filter_pred *pred)
207 {
208         int i;
209
210         if (call->preds && !pred->compound)
211                 filter_free_preds(call);
212
213         if (!call->preds) {
214                 call->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
215                                       GFP_KERNEL);
216                 if (!call->preds)
217                         return -ENOMEM;
218         }
219
220         for (i = 0; i < MAX_FILTER_PRED; i++) {
221                 if (!call->preds[i]) {
222                         call->preds[i] = pred;
223                         return 0;
224                 }
225         }
226
227         return -ENOMEM;
228 }
229
230 static int is_string_field(const char *type)
231 {
232         if (strchr(type, '[') && strstr(type, "char"))
233                 return 1;
234
235         return 0;
236 }
237
238 int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
239 {
240         struct ftrace_event_field *field;
241
242         field = find_event_field(call, pred->field_name);
243         if (!field)
244                 return -EINVAL;
245
246         pred->offset = field->offset;
247
248         if (is_string_field(field->type)) {
249                 pred->fn = filter_pred_string;
250                 pred->str_len = field->size;
251                 return __filter_add_pred(call, pred);
252         }
253
254         switch (field->size) {
255         case 8:
256                 pred->fn = filter_pred_64;
257                 break;
258         case 4:
259                 pred->fn = filter_pred_32;
260                 break;
261         case 2:
262                 pred->fn = filter_pred_16;
263                 break;
264         case 1:
265                 pred->fn = filter_pred_8;
266                 break;
267         default:
268                 return -EINVAL;
269         }
270
271         return __filter_add_pred(call, pred);
272 }
273
274 static struct filter_pred *copy_pred(struct filter_pred *pred)
275 {
276         struct filter_pred *new_pred = kmalloc(sizeof(*pred), GFP_KERNEL);
277         if (!new_pred)
278                 return NULL;
279
280         memcpy(new_pred, pred, sizeof(*pred));
281         if (pred->str_val) {
282                 new_pred->str_val = kstrdup(pred->str_val, GFP_KERNEL);
283                 new_pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
284                 if (!new_pred->str_val) {
285                         kfree(new_pred);
286                         return NULL;
287                 }
288         }
289
290         return new_pred;
291 }
292
293 int filter_add_subsystem_pred(struct event_subsystem *system,
294                               struct filter_pred *pred)
295 {
296         struct ftrace_event_call *call = __start_ftrace_events;
297         struct filter_pred *event_pred;
298         int i;
299
300         if (system->preds && !pred->compound)
301                 filter_free_subsystem_preds(system);
302
303         if (!system->preds) {
304                 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
305                                         GFP_KERNEL);
306                 if (!system->preds)
307                         return -ENOMEM;
308         }
309
310         for (i = 0; i < MAX_FILTER_PRED; i++) {
311                 if (!system->preds[i]) {
312                         system->preds[i] = pred;
313                         break;
314                 }
315                 if (i == MAX_FILTER_PRED - 1)
316                         return -EINVAL;
317         }
318
319         events_for_each(call) {
320                 if (!call->name || !call->regfunc)
321                         continue;
322
323                 if (!strcmp(call->system, system->name)) {
324                         event_pred = copy_pred(pred);
325                         if (event_pred)
326                                 filter_add_pred(call, event_pred);
327                 }
328         }
329
330         return 0;
331 }
332
333 int filter_parse(char **pbuf, struct filter_pred *pred)
334 {
335         char *tmp, *tok, *val_str = NULL;
336         int tok_n = 0;
337
338         /* field ==/!= number, or/and field ==/!= number, number */
339         while ((tok = strsep(pbuf, " \n"))) {
340                 if (tok_n == 0) {
341                         if (!strcmp(tok, "0")) {
342                                 pred->clear = 1;
343                                 return 0;
344                         } else if (!strcmp(tok, "&&")) {
345                                 pred->or = 0;
346                                 pred->compound = 1;
347                         } else if (!strcmp(tok, "||")) {
348                                 pred->or = 1;
349                                 pred->compound = 1;
350                         } else
351                                 pred->field_name = tok;
352                         tok_n = 1;
353                         continue;
354                 }
355                 if (tok_n == 1) {
356                         if (!pred->field_name)
357                                 pred->field_name = tok;
358                         else if (!strcmp(tok, "!="))
359                                 pred->not = 1;
360                         else if (!strcmp(tok, "=="))
361                                 pred->not = 0;
362                         else {
363                                 pred->field_name = NULL;
364                                 return -EINVAL;
365                         }
366                         tok_n = 2;
367                         continue;
368                 }
369                 if (tok_n == 2) {
370                         if (pred->compound) {
371                                 if (!strcmp(tok, "!="))
372                                         pred->not = 1;
373                                 else if (!strcmp(tok, "=="))
374                                         pred->not = 0;
375                                 else {
376                                         pred->field_name = NULL;
377                                         return -EINVAL;
378                                 }
379                         } else {
380                                 val_str = tok;
381                                 break; /* done */
382                         }
383                         tok_n = 3;
384                         continue;
385                 }
386                 if (tok_n == 3) {
387                         val_str = tok;
388                         break; /* done */
389                 }
390         }
391
392         pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
393         if (!pred->field_name)
394                 return -ENOMEM;
395
396         pred->val = simple_strtoull(val_str, &tmp, 10);
397         if (tmp == val_str) {
398                 pred->str_val = kstrdup(val_str, GFP_KERNEL);
399                 if (!pred->str_val)
400                         return -ENOMEM;
401         }
402
403         return 0;
404 }
405
406