tracing/events: move trace point headers into include/trace/events
[deliverable/linux.git] / kernel / trace / trace_events_filter.c
CommitLineData
7ce7e424
TZ
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"
4bda2d51 27#include "trace_output.h"
7ce7e424
TZ
28
29static 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
40static 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
51static 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
62static 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
73static 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
0a19e53c
TZ
85static int filter_pred_none(struct filter_pred *pred, void *event)
86{
87 return 0;
88}
89
7ce7e424
TZ
90/* return 1 if event matches, 0 otherwise (discard) */
91int filter_match_preds(struct ftrace_event_call *call, void *rec)
92{
93 int i, matched, and_failed = 0;
94 struct filter_pred *pred;
95
0a19e53c
TZ
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;
7ce7e424
TZ
106 }
107
108 if (and_failed)
109 return 0;
110
111 return 1;
112}
17c873ec 113EXPORT_SYMBOL_GPL(filter_match_preds);
7ce7e424 114
0a19e53c
TZ
115void filter_print_preds(struct filter_pred **preds, int n_preds,
116 struct trace_seq *s)
7ce7e424 117{
7ce7e424
TZ
118 char *field_name;
119 struct filter_pred *pred;
120 int i;
121
0a19e53c 122 if (!n_preds) {
4bda2d51
TZ
123 trace_seq_printf(s, "none\n");
124 return;
7ce7e424
TZ
125 }
126
0a19e53c
TZ
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);
7ce7e424 138 }
7ce7e424
TZ
139}
140
141static struct ftrace_event_field *
142find_event_field(struct ftrace_event_call *call, char *name)
143{
1fc2d5c1 144 struct ftrace_event_field *field;
7ce7e424 145
1fc2d5c1 146 list_for_each_entry(field, &call->fields, link) {
7ce7e424
TZ
147 if (!strcmp(field->name, name))
148 return field;
149 }
150
151 return NULL;
152}
153
154void filter_free_pred(struct filter_pred *pred)
155{
156 if (!pred)
157 return;
158
159 kfree(pred->field_name);
7ce7e424
TZ
160 kfree(pred);
161}
162
0a19e53c
TZ
163static 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
170static 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
183void filter_disable_preds(struct ftrace_event_call *call)
7ce7e424
TZ
184{
185 int i;
186
0a19e53c
TZ
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
193int 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
214oom:
215 for (i = 0; i < MAX_FILTER_PRED; i++) {
216 if (call->preds[i])
7ce7e424 217 filter_free_pred(call->preds[i]);
7ce7e424 218 }
0a19e53c
TZ
219 kfree(call->preds);
220 call->preds = NULL;
221
222 return -ENOMEM;
7ce7e424 223}
17c873ec 224EXPORT_SYMBOL_GPL(init_preds);
7ce7e424 225
cfb180f3
TZ
226void filter_free_subsystem_preds(struct event_subsystem *system)
227{
a59fd602 228 struct ftrace_event_call *call;
cfb180f3
TZ
229 int i;
230
0a19e53c
TZ
231 if (system->n_preds) {
232 for (i = 0; i < system->n_preds; i++)
cfb180f3
TZ
233 filter_free_pred(system->preds[i]);
234 kfree(system->preds);
235 system->preds = NULL;
0a19e53c 236 system->n_preds = 0;
cfb180f3
TZ
237 }
238
a59fd602 239 list_for_each_entry(call, &ftrace_events, list) {
e1112b4d 240 if (!call->define_fields)
cfb180f3
TZ
241 continue;
242
243 if (!strcmp(call->system, system->name))
0a19e53c 244 filter_disable_preds(call);
cfb180f3
TZ
245 }
246}
247
7ce7e424 248static int __filter_add_pred(struct ftrace_event_call *call,
0a19e53c
TZ
249 struct filter_pred *pred,
250 filter_pred_fn_t fn)
7ce7e424 251{
0a19e53c 252 int idx, err;
7ce7e424 253
0a19e53c
TZ
254 if (call->n_preds && !pred->compound)
255 filter_disable_preds(call);
7ce7e424 256
0a19e53c
TZ
257 if (call->n_preds == MAX_FILTER_PRED)
258 return -ENOSPC;
7ce7e424 259
0a19e53c
TZ
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++;
7ce7e424 267
0a19e53c 268 return 0;
7ce7e424
TZ
269}
270
271static int is_string_field(const char *type)
272{
273 if (strchr(type, '[') && strstr(type, "char"))
274 return 1;
275
276 return 0;
277}
278
279int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
280{
281 struct ftrace_event_field *field;
0a19e53c 282 filter_pred_fn_t fn;
7ce7e424
TZ
283
284 field = find_event_field(call, pred->field_name);
285 if (!field)
286 return -EINVAL;
287
0a19e53c 288 pred->fn = filter_pred_none;
7ce7e424
TZ
289 pred->offset = field->offset;
290
291 if (is_string_field(field->type)) {
0a19e53c 292 if (!pred->str_len)
9f58a159 293 return -EINVAL;
0a19e53c 294 fn = filter_pred_string;
7ce7e424 295 pred->str_len = field->size;
0a19e53c 296 return __filter_add_pred(call, pred, fn);
9f58a159 297 } else {
0a19e53c 298 if (pred->str_len)
9f58a159 299 return -EINVAL;
7ce7e424
TZ
300 }
301
302 switch (field->size) {
303 case 8:
0a19e53c 304 fn = filter_pred_64;
7ce7e424
TZ
305 break;
306 case 4:
0a19e53c 307 fn = filter_pred_32;
7ce7e424
TZ
308 break;
309 case 2:
0a19e53c 310 fn = filter_pred_16;
7ce7e424
TZ
311 break;
312 case 1:
0a19e53c 313 fn = filter_pred_8;
7ce7e424
TZ
314 break;
315 default:
316 return -EINVAL;
317 }
318
0a19e53c 319 return __filter_add_pred(call, pred, fn);
cfb180f3
TZ
320}
321
322int filter_add_subsystem_pred(struct event_subsystem *system,
323 struct filter_pred *pred)
324{
a59fd602 325 struct ftrace_event_call *call;
cfb180f3 326
0a19e53c 327 if (system->n_preds && !pred->compound)
cfb180f3
TZ
328 filter_free_subsystem_preds(system);
329
0a19e53c 330 if (!system->n_preds) {
cfb180f3
TZ
331 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
332 GFP_KERNEL);
333 if (!system->preds)
334 return -ENOMEM;
335 }
336
0a19e53c 337 if (system->n_preds == MAX_FILTER_PRED)
44e9c8b7 338 return -ENOSPC;
c4cff064 339
0a19e53c
TZ
340 system->preds[system->n_preds] = pred;
341
a59fd602 342 list_for_each_entry(call, &ftrace_events, list) {
c4cff064
TZ
343 int err;
344
e1112b4d 345 if (!call->define_fields)
cfb180f3
TZ
346 continue;
347
c4cff064
TZ
348 if (strcmp(call->system, system->name))
349 continue;
350
351 if (!find_event_field(call, pred->field_name))
352 continue;
353
0a19e53c
TZ
354 err = filter_add_pred(call, pred);
355 if (err == -ENOMEM) {
356 system->preds[system->n_preds] = NULL;
357 return err;
358 }
cfb180f3
TZ
359 }
360
0a19e53c 361 system->n_preds++;
c4cff064 362
0a19e53c 363 return 0;
cfb180f3
TZ
364}
365
7ce7e424
TZ
366int 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
0a19e53c
TZ
425 if (!val_str || !strlen(val_str)
426 || strlen(val_str) >= MAX_FILTER_STR_VAL) {
bcabd91c
LZ
427 pred->field_name = NULL;
428 return -EINVAL;
429 }
430
7ce7e424
TZ
431 pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
432 if (!pred->field_name)
433 return -ENOMEM;
434
0a19e53c 435 pred->str_len = 0;
a3e0ab05 436 pred->val = simple_strtoull(val_str, &tmp, 0);
7ce7e424 437 if (tmp == val_str) {
0a19e53c
TZ
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';
a3e0ab05
LZ
441 } else if (*tmp != '\0')
442 return -EINVAL;
7ce7e424
TZ
443
444 return 0;
445}
446
447
This page took 0.055646 seconds and 5 git commands to generate.