tracing/filters: fix bug in copy_pred()
[linux-2.6.git] / 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, *next;
151
152         list_for_each_entry_safe(field, next, &call->fields, link) {
153                 if (!strcmp(field->name, name))
154                         return field;
155         }
156
157         return NULL;
158 }
159
160 void filter_free_pred(struct filter_pred *pred)
161 {
162         if (!pred)
163                 return;
164
165         kfree(pred->field_name);
166         kfree(pred->str_val);
167         kfree(pred);
168 }
169
170 void filter_free_preds(struct ftrace_event_call *call)
171 {
172         int i;
173
174         if (call->preds) {
175                 for (i = 0; i < MAX_FILTER_PRED; i++)
176                         filter_free_pred(call->preds[i]);
177                 kfree(call->preds);
178                 call->preds = NULL;
179         }
180 }
181
182 void filter_free_subsystem_preds(struct event_subsystem *system)
183 {
184         struct ftrace_event_call *call = __start_ftrace_events;
185         int i;
186
187         if (system->preds) {
188                 for (i = 0; i < MAX_FILTER_PRED; i++)
189                         filter_free_pred(system->preds[i]);
190                 kfree(system->preds);
191                 system->preds = NULL;
192         }
193
194         events_for_each(call) {
195                 if (!call->name || !call->regfunc)
196                         continue;
197
198                 if (!strcmp(call->system, system->name))
199                         filter_free_preds(call);
200         }
201 }
202
203 static int __filter_add_pred(struct ftrace_event_call *call,
204                              struct filter_pred *pred)
205 {
206         int i;
207
208         if (call->preds && !pred->compound)
209                 filter_free_preds(call);
210
211         if (!call->preds) {
212                 call->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
213                                       GFP_KERNEL);
214                 if (!call->preds)
215                         return -ENOMEM;
216         }
217
218         for (i = 0; i < MAX_FILTER_PRED; i++) {
219                 if (!call->preds[i]) {
220                         call->preds[i] = pred;
221                         return 0;
222                 }
223         }
224
225         return -ENOMEM;
226 }
227
228 static int is_string_field(const char *type)
229 {
230         if (strchr(type, '[') && strstr(type, "char"))
231                 return 1;
232
233         return 0;
234 }
235
236 int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
237 {
238         struct ftrace_event_field *field;
239
240         field = find_event_field(call, pred->field_name);
241         if (!field)
242                 return -EINVAL;
243
244         pred->offset = field->offset;
245
246         if (is_string_field(field->type)) {
247                 pred->fn = filter_pred_string;
248                 pred->str_len = field->size;
249                 return __filter_add_pred(call, pred);
250         }
251
252         switch (field->size) {
253         case 8:
254                 pred->fn = filter_pred_64;
255                 break;
256         case 4:
257                 pred->fn = filter_pred_32;
258                 break;
259         case 2:
260                 pred->fn = filter_pred_16;
261                 break;
262         case 1:
263                 pred->fn = filter_pred_8;
264                 break;
265         default:
266                 return -EINVAL;
267         }
268
269         return __filter_add_pred(call, pred);
270 }
271
272 static struct filter_pred *copy_pred(struct filter_pred *pred)
273 {
274         struct filter_pred *new_pred = kmalloc(sizeof(*pred), GFP_KERNEL);
275         if (!new_pred)
276                 return NULL;
277
278         memcpy(new_pred, pred, sizeof(*pred));
279
280         if (pred->field_name) {
281                 new_pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
282                 if (!new_pred->field_name) {
283                         kfree(new_pred);
284                         return NULL;
285                 }
286         }
287
288         if (pred->str_val) {
289                 new_pred->str_val = kstrdup(pred->str_val, GFP_KERNEL);
290                 if (!new_pred->str_val) {
291                         filter_free_pred(new_pred);
292                         return NULL;
293                 }
294         }
295
296         return new_pred;
297 }
298
299 int filter_add_subsystem_pred(struct event_subsystem *system,
300                               struct filter_pred *pred)
301 {
302         struct ftrace_event_call *call = __start_ftrace_events;
303         struct filter_pred *event_pred;
304         int i;
305
306         if (system->preds && !pred->compound)
307                 filter_free_subsystem_preds(system);
308
309         if (!system->preds) {
310                 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
311                                         GFP_KERNEL);
312                 if (!system->preds)
313                         return -ENOMEM;
314         }
315
316         for (i = 0; i < MAX_FILTER_PRED; i++) {
317                 if (!system->preds[i]) {
318                         system->preds[i] = pred;
319                         break;
320                 }
321                 if (i == MAX_FILTER_PRED - 1)
322                         return -EINVAL;
323         }
324
325         events_for_each(call) {
326                 if (!call->name || !call->regfunc)
327                         continue;
328
329                 if (!strcmp(call->system, system->name)) {
330                         event_pred = copy_pred(pred);
331                         if (event_pred)
332                                 filter_add_pred(call, event_pred);
333                 }
334         }
335
336         return 0;
337 }
338
339 int filter_parse(char **pbuf, struct filter_pred *pred)
340 {
341         char *tmp, *tok, *val_str = NULL;
342         int tok_n = 0;
343
344         /* field ==/!= number, or/and field ==/!= number, number */
345         while ((tok = strsep(pbuf, " \n"))) {
346                 if (tok_n == 0) {
347                         if (!strcmp(tok, "0")) {
348                                 pred->clear = 1;
349                                 return 0;
350                         } else if (!strcmp(tok, "&&")) {
351                                 pred->or = 0;
352                                 pred->compound = 1;
353                         } else if (!strcmp(tok, "||")) {
354                                 pred->or = 1;
355                                 pred->compound = 1;
356                         } else
357                                 pred->field_name = tok;
358                         tok_n = 1;
359                         continue;
360                 }
361                 if (tok_n == 1) {
362                         if (!pred->field_name)
363                                 pred->field_name = tok;
364                         else if (!strcmp(tok, "!="))
365                                 pred->not = 1;
366                         else if (!strcmp(tok, "=="))
367                                 pred->not = 0;
368                         else {
369                                 pred->field_name = NULL;
370                                 return -EINVAL;
371                         }
372                         tok_n = 2;
373                         continue;
374                 }
375                 if (tok_n == 2) {
376                         if (pred->compound) {
377                                 if (!strcmp(tok, "!="))
378                                         pred->not = 1;
379                                 else if (!strcmp(tok, "=="))
380                                         pred->not = 0;
381                                 else {
382                                         pred->field_name = NULL;
383                                         return -EINVAL;
384                                 }
385                         } else {
386                                 val_str = tok;
387                                 break; /* done */
388                         }
389                         tok_n = 3;
390                         continue;
391                 }
392                 if (tok_n == 3) {
393                         val_str = tok;
394                         break; /* done */
395                 }
396         }
397
398         pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
399         if (!pred->field_name)
400                 return -ENOMEM;
401
402         pred->val = simple_strtoull(val_str, &tmp, 10);
403         if (tmp == val_str) {
404                 pred->str_val = kstrdup(val_str, GFP_KERNEL);
405                 if (!pred->str_val)
406                         return -ENOMEM;
407         }
408
409         return 0;
410 }
411
412