CacheFiles: Fixup renamed filenames in comments in internal.h
[linux-2.6/mini2440.git] / kernel / trace / trace_events_filter.c
blobe03cbf1e38f36b306f8eafd2ed2d79837b901a37
1 /*
2 * trace_events_filter - generic event filtering
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.
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.
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.
18 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
21 #include <linux/debugfs.h>
22 #include <linux/uaccess.h>
23 #include <linux/module.h>
24 #include <linux/ctype.h>
26 #include "trace.h"
27 #include "trace_output.h"
29 static int filter_pred_64(struct filter_pred *pred, void *event)
31 u64 *addr = (u64 *)(event + pred->offset);
32 u64 val = (u64)pred->val;
33 int match;
35 match = (val == *addr) ^ pred->not;
37 return match;
40 static int filter_pred_32(struct filter_pred *pred, void *event)
42 u32 *addr = (u32 *)(event + pred->offset);
43 u32 val = (u32)pred->val;
44 int match;
46 match = (val == *addr) ^ pred->not;
48 return match;
51 static int filter_pred_16(struct filter_pred *pred, void *event)
53 u16 *addr = (u16 *)(event + pred->offset);
54 u16 val = (u16)pred->val;
55 int match;
57 match = (val == *addr) ^ pred->not;
59 return match;
62 static int filter_pred_8(struct filter_pred *pred, void *event)
64 u8 *addr = (u8 *)(event + pred->offset);
65 u8 val = (u8)pred->val;
66 int match;
68 match = (val == *addr) ^ pred->not;
70 return match;
73 static int filter_pred_string(struct filter_pred *pred, void *event)
75 char *addr = (char *)(event + pred->offset);
76 int cmp, match;
78 cmp = strncmp(addr, pred->str_val, pred->str_len);
80 match = (!cmp) ^ pred->not;
82 return match;
85 /* return 1 if event matches, 0 otherwise (discard) */
86 int filter_match_preds(struct ftrace_event_call *call, void *rec)
88 int i, matched, and_failed = 0;
89 struct filter_pred *pred;
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;
106 if (and_failed)
107 return 0;
109 return 1;
112 void filter_print_preds(struct filter_pred **preds, struct trace_seq *s)
114 char *field_name;
115 struct filter_pred *pred;
116 int i;
118 if (!preds) {
119 trace_seq_printf(s, "none\n");
120 return;
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;
140 static struct ftrace_event_field *
141 find_event_field(struct ftrace_event_call *call, char *name)
143 struct ftrace_event_field *field;
145 list_for_each_entry(field, &call->fields, link) {
146 if (!strcmp(field->name, name))
147 return field;
150 return NULL;
153 void filter_free_pred(struct filter_pred *pred)
155 if (!pred)
156 return;
158 kfree(pred->field_name);
159 kfree(pred->str_val);
160 kfree(pred);
163 void filter_free_preds(struct ftrace_event_call *call)
165 int i;
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;
175 void filter_free_subsystem_preds(struct event_subsystem *system)
177 struct ftrace_event_call *call = __start_ftrace_events;
178 int i;
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;
187 events_for_each(call) {
188 if (!call->name || !call->regfunc)
189 continue;
191 if (!strcmp(call->system, system->name))
192 filter_free_preds(call);
196 static int __filter_add_pred(struct ftrace_event_call *call,
197 struct filter_pred *pred)
199 int i;
201 if (call->preds && !pred->compound)
202 filter_free_preds(call);
204 if (!call->preds) {
205 call->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
206 GFP_KERNEL);
207 if (!call->preds)
208 return -ENOMEM;
211 for (i = 0; i < MAX_FILTER_PRED; i++) {
212 if (!call->preds[i]) {
213 call->preds[i] = pred;
214 return 0;
218 return -ENOSPC;
221 static int is_string_field(const char *type)
223 if (strchr(type, '[') && strstr(type, "char"))
224 return 1;
226 return 0;
229 int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
231 struct ftrace_event_field *field;
233 field = find_event_field(call, pred->field_name);
234 if (!field)
235 return -EINVAL;
237 pred->offset = field->offset;
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;
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;
267 return __filter_add_pred(call, pred);
270 static struct filter_pred *copy_pred(struct filter_pred *pred)
272 struct filter_pred *new_pred = kmalloc(sizeof(*pred), GFP_KERNEL);
273 if (!new_pred)
274 return NULL;
276 memcpy(new_pred, pred, sizeof(*pred));
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;
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;
294 return new_pred;
297 int filter_add_subsystem_pred(struct event_subsystem *system,
298 struct filter_pred *pred)
300 struct ftrace_event_call *call = __start_ftrace_events;
301 struct filter_pred *event_pred;
302 int i;
304 if (system->preds && !pred->compound)
305 filter_free_subsystem_preds(system);
307 if (!system->preds) {
308 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
309 GFP_KERNEL);
310 if (!system->preds)
311 return -ENOMEM;
314 for (i = 0; i < MAX_FILTER_PRED; i++) {
315 if (!system->preds[i]) {
316 system->preds[i] = pred;
317 break;
321 if (i == MAX_FILTER_PRED)
322 return -ENOSPC;
324 events_for_each(call) {
325 int err;
327 if (!call->name || !call->regfunc)
328 continue;
330 if (strcmp(call->system, system->name))
331 continue;
333 if (!find_event_field(call, pred->field_name))
334 continue;
336 event_pred = copy_pred(pred);
337 if (!event_pred)
338 goto oom;
340 err = filter_add_pred(call, event_pred);
341 if (err)
342 filter_free_pred(event_pred);
343 if (err == -ENOMEM)
344 goto oom;
347 return 0;
349 oom:
350 system->preds[i] = NULL;
351 return -ENOMEM;
354 int filter_parse(char **pbuf, struct filter_pred *pred)
356 char *tmp, *tok, *val_str = NULL;
357 int tok_n = 0;
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;
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;
387 tok_n = 2;
388 continue;
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;
400 } else {
401 val_str = tok;
402 break; /* done */
404 tok_n = 3;
405 continue;
407 if (tok_n == 3) {
408 val_str = tok;
409 break; /* done */
413 if (!val_str) {
414 pred->field_name = NULL;
415 return -EINVAL;
418 pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
419 if (!pred->field_name)
420 return -ENOMEM;
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;
430 return 0;