tracing/filters: allow user input integer to be oct or hex
[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 /* return 1 if event matches, 0 otherwise (discard) */
86 int filter_match_preds(struct ftrace_event_call *call, void *rec)
87 {
88         int i, matched, and_failed = 0;
89         struct filter_pred *pred;
90
91         for (i = 0; i < MAX_FILTER_PRED; i++) {
92                 if (call->preds[i]) {
93                         pred = call->preds[i];
94                         if (and_failed && !pred->or)
95                                 continue;
96                         matched = pred->fn(pred, rec);
97                         if (!matched && !pred->or) {
98                                 and_failed = 1;
99                                 continue;
100                         } else if (matched && pred->or)
101                                 return 1;
102                 } else
103                         break;
104         }
105
106         if (and_failed)
107                 return 0;
108
109         return 1;
110 }
111
112 void filter_print_preds(struct filter_pred **preds, struct trace_seq *s)
113 {
114         char *field_name;
115         struct filter_pred *pred;
116         int i;
117
118         if (!preds) {
119                 trace_seq_printf(s, "none\n");
120                 return;
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                                 trace_seq_printf(s, pred->or ? "|| " : "&& ");
129                         trace_seq_printf(s, "%s ", field_name);
130                         trace_seq_printf(s, pred->not ? "!= " : "== ");
131                         if (pred->str_val)
132                                 trace_seq_printf(s, "%s\n", pred->str_val);
133                         else
134                                 trace_seq_printf(s, "%llu\n", pred->val);
135                 } else
136                         break;
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->str_val);
160         kfree(pred);
161 }
162
163 void filter_free_preds(struct ftrace_event_call *call)
164 {
165         int i;
166
167         if (call->preds) {
168                 for (i = 0; i < MAX_FILTER_PRED; i++)
169                         filter_free_pred(call->preds[i]);
170                 kfree(call->preds);
171                 call->preds = NULL;
172         }
173 }
174
175 void filter_free_subsystem_preds(struct event_subsystem *system)
176 {
177         struct ftrace_event_call *call = __start_ftrace_events;
178         int i;
179
180         if (system->preds) {
181                 for (i = 0; i < MAX_FILTER_PRED; i++)
182                         filter_free_pred(system->preds[i]);
183                 kfree(system->preds);
184                 system->preds = NULL;
185         }
186
187         events_for_each(call) {
188                 if (!call->name || !call->regfunc)
189                         continue;
190
191                 if (!strcmp(call->system, system->name))
192                         filter_free_preds(call);
193         }
194 }
195
196 static int __filter_add_pred(struct ftrace_event_call *call,
197                              struct filter_pred *pred)
198 {
199         int i;
200
201         if (call->preds && !pred->compound)
202                 filter_free_preds(call);
203
204         if (!call->preds) {
205                 call->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
206                                       GFP_KERNEL);
207                 if (!call->preds)
208                         return -ENOMEM;
209         }
210
211         for (i = 0; i < MAX_FILTER_PRED; i++) {
212                 if (!call->preds[i]) {
213                         call->preds[i] = pred;
214                         return 0;
215                 }
216         }
217
218         return -ENOMEM;
219 }
220
221 static int is_string_field(const char *type)
222 {
223         if (strchr(type, '[') && strstr(type, "char"))
224                 return 1;
225
226         return 0;
227 }
228
229 int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
230 {
231         struct ftrace_event_field *field;
232
233         field = find_event_field(call, pred->field_name);
234         if (!field)
235                 return -EINVAL;
236
237         pred->offset = field->offset;
238
239         if (is_string_field(field->type)) {
240                 if (!pred->str_val)
241                         return -EINVAL;
242                 pred->fn = filter_pred_string;
243                 pred->str_len = field->size;
244                 return __filter_add_pred(call, pred);
245         } else {
246                 if (pred->str_val)
247                         return -EINVAL;
248         }
249
250         switch (field->size) {
251         case 8:
252                 pred->fn = filter_pred_64;
253                 break;
254         case 4:
255                 pred->fn = filter_pred_32;
256                 break;
257         case 2:
258                 pred->fn = filter_pred_16;
259                 break;
260         case 1:
261                 pred->fn = filter_pred_8;
262                 break;
263         default:
264                 return -EINVAL;
265         }
266
267         return __filter_add_pred(call, pred);
268 }
269
270 static struct filter_pred *copy_pred(struct filter_pred *pred)
271 {
272         struct filter_pred *new_pred = kmalloc(sizeof(*pred), GFP_KERNEL);
273         if (!new_pred)
274                 return NULL;
275
276         memcpy(new_pred, pred, sizeof(*pred));
277
278         if (pred->field_name) {
279                 new_pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
280                 if (!new_pred->field_name) {
281                         kfree(new_pred);
282                         return NULL;
283                 }
284         }
285
286         if (pred->str_val) {
287                 new_pred->str_val = kstrdup(pred->str_val, GFP_KERNEL);
288                 if (!new_pred->str_val) {
289                         filter_free_pred(new_pred);
290                         return NULL;
291                 }
292         }
293
294         return new_pred;
295 }
296
297 int filter_add_subsystem_pred(struct event_subsystem *system,
298                               struct filter_pred *pred)
299 {
300         struct ftrace_event_call *call = __start_ftrace_events;
301         struct filter_pred *event_pred;
302         int i;
303
304         if (system->preds && !pred->compound)
305                 filter_free_subsystem_preds(system);
306
307         if (!system->preds) {
308                 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
309                                         GFP_KERNEL);
310                 if (!system->preds)
311                         return -ENOMEM;
312         }
313
314         for (i = 0; i < MAX_FILTER_PRED; i++) {
315                 if (!system->preds[i]) {
316                         system->preds[i] = pred;
317                         break;
318                 }
319         }
320
321         if (i == MAX_FILTER_PRED)
322                 return -EINVAL;
323
324         events_for_each(call) {
325                 int err;
326
327                 if (!call->name || !call->regfunc)
328                         continue;
329
330                 if (strcmp(call->system, system->name))
331                         continue;
332
333                 if (!find_event_field(call, pred->field_name))
334                         continue;
335
336                 event_pred = copy_pred(pred);
337                 if (!event_pred)
338                         goto oom;
339
340                 err = filter_add_pred(call, event_pred);
341                 if (err)
342                         filter_free_pred(event_pred);
343                 if (err == -ENOMEM)
344                         goto oom;
345         }
346
347         return 0;
348
349 oom:
350         system->preds[i] = NULL;
351         return -ENOMEM;
352 }
353
354 int filter_parse(char **pbuf, struct filter_pred *pred)
355 {
356         char *tmp, *tok, *val_str = NULL;
357         int tok_n = 0;
358
359         /* field ==/!= number, or/and field ==/!= number, number */
360         while ((tok = strsep(pbuf, " \n"))) {
361                 if (tok_n == 0) {
362                         if (!strcmp(tok, "0")) {
363                                 pred->clear = 1;
364                                 return 0;
365                         } else if (!strcmp(tok, "&&")) {
366                                 pred->or = 0;
367                                 pred->compound = 1;
368                         } else if (!strcmp(tok, "||")) {
369                                 pred->or = 1;
370                                 pred->compound = 1;
371                         } else
372                                 pred->field_name = tok;
373                         tok_n = 1;
374                         continue;
375                 }
376                 if (tok_n == 1) {
377                         if (!pred->field_name)
378                                 pred->field_name = tok;
379                         else if (!strcmp(tok, "!="))
380                                 pred->not = 1;
381                         else if (!strcmp(tok, "=="))
382                                 pred->not = 0;
383                         else {
384                                 pred->field_name = NULL;
385                                 return -EINVAL;
386                         }
387                         tok_n = 2;
388                         continue;
389                 }
390                 if (tok_n == 2) {
391                         if (pred->compound) {
392                                 if (!strcmp(tok, "!="))
393                                         pred->not = 1;
394                                 else if (!strcmp(tok, "=="))
395                                         pred->not = 0;
396                                 else {
397                                         pred->field_name = NULL;
398                                         return -EINVAL;
399                                 }
400                         } else {
401                                 val_str = tok;
402                                 break; /* done */
403                         }
404                         tok_n = 3;
405                         continue;
406                 }
407                 if (tok_n == 3) {
408                         val_str = tok;
409                         break; /* done */
410                 }
411         }
412
413         if (!val_str) {
414                 pred->field_name = NULL;
415                 return -EINVAL;
416         }
417
418         pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
419         if (!pred->field_name)
420                 return -ENOMEM;
421
422         pred->val = simple_strtoull(val_str, &tmp, 0);
423         if (tmp == val_str) {
424                 pred->str_val = kstrdup(val_str, GFP_KERNEL);
425                 if (!pred->str_val)
426                         return -ENOMEM;
427         } else if (*tmp != '\0')
428                 return -EINVAL;
429
430         return 0;
431 }
432
433