]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - kernel/trace/trace_events_filter.c
tracing/filters: distinguish between signed and unsigned fields
[mirror_ubuntu-artful-kernel.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>
ac1adc55 25#include <linux/mutex.h>
7ce7e424
TZ
26
27#include "trace.h"
4bda2d51 28#include "trace_output.h"
7ce7e424 29
ac1adc55
TZ
30static DEFINE_MUTEX(filter_mutex);
31
7ce7e424
TZ
32static int filter_pred_64(struct filter_pred *pred, void *event)
33{
34 u64 *addr = (u64 *)(event + pred->offset);
35 u64 val = (u64)pred->val;
36 int match;
37
38 match = (val == *addr) ^ pred->not;
39
40 return match;
41}
42
43static int filter_pred_32(struct filter_pred *pred, void *event)
44{
45 u32 *addr = (u32 *)(event + pred->offset);
46 u32 val = (u32)pred->val;
47 int match;
48
49 match = (val == *addr) ^ pred->not;
50
51 return match;
52}
53
54static int filter_pred_16(struct filter_pred *pred, void *event)
55{
56 u16 *addr = (u16 *)(event + pred->offset);
57 u16 val = (u16)pred->val;
58 int match;
59
60 match = (val == *addr) ^ pred->not;
61
62 return match;
63}
64
65static int filter_pred_8(struct filter_pred *pred, void *event)
66{
67 u8 *addr = (u8 *)(event + pred->offset);
68 u8 val = (u8)pred->val;
69 int match;
70
71 match = (val == *addr) ^ pred->not;
72
73 return match;
74}
75
76static int filter_pred_string(struct filter_pred *pred, void *event)
77{
78 char *addr = (char *)(event + pred->offset);
79 int cmp, match;
80
81 cmp = strncmp(addr, pred->str_val, pred->str_len);
82
83 match = (!cmp) ^ pred->not;
84
85 return match;
86}
87
0a19e53c
TZ
88static int filter_pred_none(struct filter_pred *pred, void *event)
89{
90 return 0;
91}
92
7ce7e424
TZ
93/* return 1 if event matches, 0 otherwise (discard) */
94int filter_match_preds(struct ftrace_event_call *call, void *rec)
95{
30e673b2 96 struct event_filter *filter = call->filter;
7ce7e424
TZ
97 int i, matched, and_failed = 0;
98 struct filter_pred *pred;
99
30e673b2
TZ
100 for (i = 0; i < filter->n_preds; i++) {
101 pred = filter->preds[i];
0a19e53c
TZ
102 if (and_failed && !pred->or)
103 continue;
104 matched = pred->fn(pred, rec);
105 if (!matched && !pred->or) {
106 and_failed = 1;
107 continue;
108 } else if (matched && pred->or)
109 return 1;
7ce7e424
TZ
110 }
111
112 if (and_failed)
113 return 0;
114
115 return 1;
116}
17c873ec 117EXPORT_SYMBOL_GPL(filter_match_preds);
7ce7e424 118
30e673b2 119static void __filter_print_preds(struct event_filter *filter,
ac1adc55 120 struct trace_seq *s)
7ce7e424 121{
7ce7e424 122 struct filter_pred *pred;
30e673b2 123 char *field_name;
7ce7e424
TZ
124 int i;
125
30e673b2 126 if (!filter || !filter->n_preds) {
4bda2d51
TZ
127 trace_seq_printf(s, "none\n");
128 return;
7ce7e424
TZ
129 }
130
30e673b2
TZ
131 for (i = 0; i < filter->n_preds; i++) {
132 pred = filter->preds[i];
0a19e53c
TZ
133 field_name = pred->field_name;
134 if (i)
135 trace_seq_printf(s, pred->or ? "|| " : "&& ");
136 trace_seq_printf(s, "%s ", field_name);
137 trace_seq_printf(s, pred->not ? "!= " : "== ");
138 if (pred->str_len)
139 trace_seq_printf(s, "%s\n", pred->str_val);
140 else
141 trace_seq_printf(s, "%llu\n", pred->val);
7ce7e424 142 }
7ce7e424
TZ
143}
144
ac1adc55
TZ
145void filter_print_preds(struct ftrace_event_call *call, struct trace_seq *s)
146{
147 mutex_lock(&filter_mutex);
30e673b2 148 __filter_print_preds(call->filter, s);
ac1adc55
TZ
149 mutex_unlock(&filter_mutex);
150}
151
152void filter_print_subsystem_preds(struct event_subsystem *system,
153 struct trace_seq *s)
154{
155 mutex_lock(&filter_mutex);
30e673b2 156 __filter_print_preds(system->filter, s);
ac1adc55
TZ
157 mutex_unlock(&filter_mutex);
158}
159
7ce7e424
TZ
160static struct ftrace_event_field *
161find_event_field(struct ftrace_event_call *call, char *name)
162{
1fc2d5c1 163 struct ftrace_event_field *field;
7ce7e424 164
1fc2d5c1 165 list_for_each_entry(field, &call->fields, link) {
7ce7e424
TZ
166 if (!strcmp(field->name, name))
167 return field;
168 }
169
170 return NULL;
171}
172
173void filter_free_pred(struct filter_pred *pred)
174{
175 if (!pred)
176 return;
177
178 kfree(pred->field_name);
7ce7e424
TZ
179 kfree(pred);
180}
181
0a19e53c
TZ
182static void filter_clear_pred(struct filter_pred *pred)
183{
184 kfree(pred->field_name);
185 pred->field_name = NULL;
186 pred->str_len = 0;
187}
188
189static int filter_set_pred(struct filter_pred *dest,
190 struct filter_pred *src,
191 filter_pred_fn_t fn)
192{
193 *dest = *src;
194 dest->field_name = kstrdup(src->field_name, GFP_KERNEL);
195 if (!dest->field_name)
196 return -ENOMEM;
197 dest->fn = fn;
198
199 return 0;
200}
201
ac1adc55 202static void __filter_disable_preds(struct ftrace_event_call *call)
7ce7e424 203{
30e673b2 204 struct event_filter *filter = call->filter;
7ce7e424
TZ
205 int i;
206
30e673b2
TZ
207 call->filter_active = 0;
208 filter->n_preds = 0;
0a19e53c
TZ
209
210 for (i = 0; i < MAX_FILTER_PRED; i++)
30e673b2 211 filter->preds[i]->fn = filter_pred_none;
0a19e53c
TZ
212}
213
ac1adc55
TZ
214void filter_disable_preds(struct ftrace_event_call *call)
215{
216 mutex_lock(&filter_mutex);
217 __filter_disable_preds(call);
218 mutex_unlock(&filter_mutex);
219}
220
0a19e53c
TZ
221int init_preds(struct ftrace_event_call *call)
222{
30e673b2 223 struct event_filter *filter;
0a19e53c
TZ
224 struct filter_pred *pred;
225 int i;
226
30e673b2
TZ
227 filter = call->filter = kzalloc(sizeof(*filter), GFP_KERNEL);
228 if (!call->filter)
0a19e53c
TZ
229 return -ENOMEM;
230
30e673b2
TZ
231 call->filter_active = 0;
232 filter->n_preds = 0;
233
234 filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL);
235 if (!filter->preds)
236 goto oom;
237
0a19e53c
TZ
238 for (i = 0; i < MAX_FILTER_PRED; i++) {
239 pred = kzalloc(sizeof(*pred), GFP_KERNEL);
240 if (!pred)
241 goto oom;
242 pred->fn = filter_pred_none;
30e673b2 243 filter->preds[i] = pred;
0a19e53c
TZ
244 }
245
246 return 0;
247
248oom:
249 for (i = 0; i < MAX_FILTER_PRED; i++) {
30e673b2
TZ
250 if (filter->preds[i])
251 filter_free_pred(filter->preds[i]);
7ce7e424 252 }
30e673b2
TZ
253 kfree(filter->preds);
254 kfree(call->filter);
255 call->filter = NULL;
0a19e53c
TZ
256
257 return -ENOMEM;
7ce7e424 258}
17c873ec 259EXPORT_SYMBOL_GPL(init_preds);
7ce7e424 260
ac1adc55 261static void __filter_free_subsystem_preds(struct event_subsystem *system)
cfb180f3 262{
30e673b2 263 struct event_filter *filter = system->filter;
a59fd602 264 struct ftrace_event_call *call;
cfb180f3
TZ
265 int i;
266
30e673b2
TZ
267 if (filter && filter->n_preds) {
268 for (i = 0; i < filter->n_preds; i++)
269 filter_free_pred(filter->preds[i]);
270 kfree(filter->preds);
271 kfree(filter);
272 system->filter = NULL;
cfb180f3
TZ
273 }
274
a59fd602 275 list_for_each_entry(call, &ftrace_events, list) {
e1112b4d 276 if (!call->define_fields)
cfb180f3
TZ
277 continue;
278
279 if (!strcmp(call->system, system->name))
ac1adc55 280 __filter_disable_preds(call);
cfb180f3
TZ
281 }
282}
283
ac1adc55
TZ
284void filter_free_subsystem_preds(struct event_subsystem *system)
285{
286 mutex_lock(&filter_mutex);
287 __filter_free_subsystem_preds(system);
288 mutex_unlock(&filter_mutex);
289}
290
291static int filter_add_pred_fn(struct ftrace_event_call *call,
292 struct filter_pred *pred,
293 filter_pred_fn_t fn)
7ce7e424 294{
30e673b2 295 struct event_filter *filter = call->filter;
0a19e53c 296 int idx, err;
7ce7e424 297
30e673b2 298 if (filter->n_preds && !pred->compound)
ac1adc55 299 __filter_disable_preds(call);
7ce7e424 300
30e673b2 301 if (filter->n_preds == MAX_FILTER_PRED)
0a19e53c 302 return -ENOSPC;
7ce7e424 303
30e673b2
TZ
304 idx = filter->n_preds;
305 filter_clear_pred(filter->preds[idx]);
306 err = filter_set_pred(filter->preds[idx], pred, fn);
0a19e53c
TZ
307 if (err)
308 return err;
309
30e673b2
TZ
310 filter->n_preds++;
311 call->filter_active = 1;
7ce7e424 312
0a19e53c 313 return 0;
7ce7e424
TZ
314}
315
316static int is_string_field(const char *type)
317{
318 if (strchr(type, '[') && strstr(type, "char"))
319 return 1;
320
321 return 0;
322}
323
ac1adc55
TZ
324static int __filter_add_pred(struct ftrace_event_call *call,
325 struct filter_pred *pred)
7ce7e424
TZ
326{
327 struct ftrace_event_field *field;
0a19e53c 328 filter_pred_fn_t fn;
f66578a7 329 unsigned long long val;
7ce7e424
TZ
330
331 field = find_event_field(call, pred->field_name);
332 if (!field)
333 return -EINVAL;
334
0a19e53c 335 pred->fn = filter_pred_none;
7ce7e424
TZ
336 pred->offset = field->offset;
337
338 if (is_string_field(field->type)) {
0a19e53c 339 fn = filter_pred_string;
7ce7e424 340 pred->str_len = field->size;
ac1adc55 341 return filter_add_pred_fn(call, pred, fn);
9f58a159 342 } else {
f66578a7 343 if (strict_strtoull(pred->str_val, 0, &val))
9f58a159 344 return -EINVAL;
f66578a7 345 pred->val = val;
7ce7e424
TZ
346 }
347
348 switch (field->size) {
349 case 8:
0a19e53c 350 fn = filter_pred_64;
7ce7e424
TZ
351 break;
352 case 4:
0a19e53c 353 fn = filter_pred_32;
7ce7e424
TZ
354 break;
355 case 2:
0a19e53c 356 fn = filter_pred_16;
7ce7e424
TZ
357 break;
358 case 1:
0a19e53c 359 fn = filter_pred_8;
7ce7e424
TZ
360 break;
361 default:
362 return -EINVAL;
363 }
364
ac1adc55
TZ
365 return filter_add_pred_fn(call, pred, fn);
366}
367
368int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
369{
370 int err;
371
372 mutex_lock(&filter_mutex);
373 err = __filter_add_pred(call, pred);
374 mutex_unlock(&filter_mutex);
375
376 return err;
cfb180f3
TZ
377}
378
379int filter_add_subsystem_pred(struct event_subsystem *system,
380 struct filter_pred *pred)
381{
30e673b2 382 struct event_filter *filter = system->filter;
a59fd602 383 struct ftrace_event_call *call;
cfb180f3 384
ac1adc55
TZ
385 mutex_lock(&filter_mutex);
386
30e673b2 387 if (filter && filter->n_preds && !pred->compound) {
ac1adc55 388 __filter_free_subsystem_preds(system);
30e673b2
TZ
389 filter = NULL;
390 }
cfb180f3 391
30e673b2
TZ
392 if (!filter) {
393 system->filter = kzalloc(sizeof(*filter), GFP_KERNEL);
394 if (!system->filter) {
395 mutex_unlock(&filter_mutex);
396 return -ENOMEM;
397 }
398 filter = system->filter;
399 filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
cfb180f3 400 GFP_KERNEL);
30e673b2
TZ
401
402 if (!filter->preds) {
403 kfree(system->filter);
404 system->filter = NULL;
ac1adc55 405 mutex_unlock(&filter_mutex);
cfb180f3 406 return -ENOMEM;
ac1adc55 407 }
cfb180f3
TZ
408 }
409
30e673b2 410 if (filter->n_preds == MAX_FILTER_PRED) {
ac1adc55 411 mutex_unlock(&filter_mutex);
44e9c8b7 412 return -ENOSPC;
ac1adc55 413 }
c4cff064 414
30e673b2
TZ
415 filter->preds[filter->n_preds] = pred;
416 filter->n_preds++;
0a19e53c 417
a59fd602 418 list_for_each_entry(call, &ftrace_events, list) {
c4cff064
TZ
419 int err;
420
e1112b4d 421 if (!call->define_fields)
cfb180f3
TZ
422 continue;
423
c4cff064
TZ
424 if (strcmp(call->system, system->name))
425 continue;
426
ac1adc55 427 err = __filter_add_pred(call, pred);
0a19e53c 428 if (err == -ENOMEM) {
30e673b2
TZ
429 filter->preds[filter->n_preds] = NULL;
430 filter->n_preds--;
ac1adc55 431 mutex_unlock(&filter_mutex);
0a19e53c
TZ
432 return err;
433 }
cfb180f3
TZ
434 }
435
ac1adc55 436 mutex_unlock(&filter_mutex);
c4cff064 437
0a19e53c 438 return 0;
cfb180f3
TZ
439}
440
f66578a7
LZ
441/*
442 * The filter format can be
443 * - 0, which means remove all filter preds
444 * - [||/&&] <field> ==/!= <val>
445 */
7ce7e424
TZ
446int filter_parse(char **pbuf, struct filter_pred *pred)
447{
f66578a7 448 char *tok, *val_str = NULL;
7ce7e424
TZ
449 int tok_n = 0;
450
7ce7e424
TZ
451 while ((tok = strsep(pbuf, " \n"))) {
452 if (tok_n == 0) {
453 if (!strcmp(tok, "0")) {
454 pred->clear = 1;
455 return 0;
456 } else if (!strcmp(tok, "&&")) {
457 pred->or = 0;
458 pred->compound = 1;
459 } else if (!strcmp(tok, "||")) {
460 pred->or = 1;
461 pred->compound = 1;
462 } else
463 pred->field_name = tok;
464 tok_n = 1;
465 continue;
466 }
467 if (tok_n == 1) {
468 if (!pred->field_name)
469 pred->field_name = tok;
470 else if (!strcmp(tok, "!="))
471 pred->not = 1;
472 else if (!strcmp(tok, "=="))
473 pred->not = 0;
474 else {
475 pred->field_name = NULL;
476 return -EINVAL;
477 }
478 tok_n = 2;
479 continue;
480 }
481 if (tok_n == 2) {
482 if (pred->compound) {
483 if (!strcmp(tok, "!="))
484 pred->not = 1;
485 else if (!strcmp(tok, "=="))
486 pred->not = 0;
487 else {
488 pred->field_name = NULL;
489 return -EINVAL;
490 }
491 } else {
492 val_str = tok;
493 break; /* done */
494 }
495 tok_n = 3;
496 continue;
497 }
498 if (tok_n == 3) {
499 val_str = tok;
500 break; /* done */
501 }
502 }
503
0a19e53c
TZ
504 if (!val_str || !strlen(val_str)
505 || strlen(val_str) >= MAX_FILTER_STR_VAL) {
bcabd91c
LZ
506 pred->field_name = NULL;
507 return -EINVAL;
508 }
509
f66578a7
LZ
510 strcpy(pred->str_val, val_str);
511 pred->str_len = strlen(val_str);
512
7ce7e424
TZ
513 pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
514 if (!pred->field_name)
515 return -ENOMEM;
516
7ce7e424
TZ
517 return 0;
518}
519
520