tracing: x86, mmiotrace: only register for die notifier when tracer active
[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>
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{
96 int i, matched, and_failed = 0;
97 struct filter_pred *pred;
98
0a19e53c
TZ
99 for (i = 0; i < call->n_preds; i++) {
100 pred = call->preds[i];
101 if (and_failed && !pred->or)
102 continue;
103 matched = pred->fn(pred, rec);
104 if (!matched && !pred->or) {
105 and_failed = 1;
106 continue;
107 } else if (matched && pred->or)
108 return 1;
7ce7e424
TZ
109 }
110
111 if (and_failed)
112 return 0;
113
114 return 1;
115}
17c873ec 116EXPORT_SYMBOL_GPL(filter_match_preds);
7ce7e424 117
ac1adc55
TZ
118static void __filter_print_preds(struct filter_pred **preds, int n_preds,
119 struct trace_seq *s)
7ce7e424 120{
7ce7e424
TZ
121 char *field_name;
122 struct filter_pred *pred;
123 int i;
124
0a19e53c 125 if (!n_preds) {
4bda2d51
TZ
126 trace_seq_printf(s, "none\n");
127 return;
7ce7e424
TZ
128 }
129
0a19e53c
TZ
130 for (i = 0; i < n_preds; i++) {
131 pred = preds[i];
132 field_name = pred->field_name;
133 if (i)
134 trace_seq_printf(s, pred->or ? "|| " : "&& ");
135 trace_seq_printf(s, "%s ", field_name);
136 trace_seq_printf(s, pred->not ? "!= " : "== ");
137 if (pred->str_len)
138 trace_seq_printf(s, "%s\n", pred->str_val);
139 else
140 trace_seq_printf(s, "%llu\n", pred->val);
7ce7e424 141 }
7ce7e424
TZ
142}
143
ac1adc55
TZ
144void filter_print_preds(struct ftrace_event_call *call, struct trace_seq *s)
145{
146 mutex_lock(&filter_mutex);
147 __filter_print_preds(call->preds, call->n_preds, s);
148 mutex_unlock(&filter_mutex);
149}
150
151void filter_print_subsystem_preds(struct event_subsystem *system,
152 struct trace_seq *s)
153{
154 mutex_lock(&filter_mutex);
155 __filter_print_preds(system->preds, system->n_preds, s);
156 mutex_unlock(&filter_mutex);
157}
158
7ce7e424
TZ
159static struct ftrace_event_field *
160find_event_field(struct ftrace_event_call *call, char *name)
161{
1fc2d5c1 162 struct ftrace_event_field *field;
7ce7e424 163
1fc2d5c1 164 list_for_each_entry(field, &call->fields, link) {
7ce7e424
TZ
165 if (!strcmp(field->name, name))
166 return field;
167 }
168
169 return NULL;
170}
171
172void filter_free_pred(struct filter_pred *pred)
173{
174 if (!pred)
175 return;
176
177 kfree(pred->field_name);
7ce7e424
TZ
178 kfree(pred);
179}
180
0a19e53c
TZ
181static void filter_clear_pred(struct filter_pred *pred)
182{
183 kfree(pred->field_name);
184 pred->field_name = NULL;
185 pred->str_len = 0;
186}
187
188static int filter_set_pred(struct filter_pred *dest,
189 struct filter_pred *src,
190 filter_pred_fn_t fn)
191{
192 *dest = *src;
193 dest->field_name = kstrdup(src->field_name, GFP_KERNEL);
194 if (!dest->field_name)
195 return -ENOMEM;
196 dest->fn = fn;
197
198 return 0;
199}
200
ac1adc55 201static void __filter_disable_preds(struct ftrace_event_call *call)
7ce7e424
TZ
202{
203 int i;
204
0a19e53c
TZ
205 call->n_preds = 0;
206
207 for (i = 0; i < MAX_FILTER_PRED; i++)
208 call->preds[i]->fn = filter_pred_none;
209}
210
ac1adc55
TZ
211void filter_disable_preds(struct ftrace_event_call *call)
212{
213 mutex_lock(&filter_mutex);
214 __filter_disable_preds(call);
215 mutex_unlock(&filter_mutex);
216}
217
0a19e53c
TZ
218int init_preds(struct ftrace_event_call *call)
219{
220 struct filter_pred *pred;
221 int i;
222
223 call->n_preds = 0;
224
225 call->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL);
226 if (!call->preds)
227 return -ENOMEM;
228
229 for (i = 0; i < MAX_FILTER_PRED; i++) {
230 pred = kzalloc(sizeof(*pred), GFP_KERNEL);
231 if (!pred)
232 goto oom;
233 pred->fn = filter_pred_none;
234 call->preds[i] = pred;
235 }
236
237 return 0;
238
239oom:
240 for (i = 0; i < MAX_FILTER_PRED; i++) {
241 if (call->preds[i])
7ce7e424 242 filter_free_pred(call->preds[i]);
7ce7e424 243 }
0a19e53c
TZ
244 kfree(call->preds);
245 call->preds = NULL;
246
247 return -ENOMEM;
7ce7e424 248}
17c873ec 249EXPORT_SYMBOL_GPL(init_preds);
7ce7e424 250
ac1adc55 251static void __filter_free_subsystem_preds(struct event_subsystem *system)
cfb180f3 252{
a59fd602 253 struct ftrace_event_call *call;
cfb180f3
TZ
254 int i;
255
0a19e53c
TZ
256 if (system->n_preds) {
257 for (i = 0; i < system->n_preds; i++)
cfb180f3
TZ
258 filter_free_pred(system->preds[i]);
259 kfree(system->preds);
260 system->preds = NULL;
0a19e53c 261 system->n_preds = 0;
cfb180f3
TZ
262 }
263
a59fd602 264 list_for_each_entry(call, &ftrace_events, list) {
e1112b4d 265 if (!call->define_fields)
cfb180f3
TZ
266 continue;
267
268 if (!strcmp(call->system, system->name))
ac1adc55 269 __filter_disable_preds(call);
cfb180f3
TZ
270 }
271}
272
ac1adc55
TZ
273void filter_free_subsystem_preds(struct event_subsystem *system)
274{
275 mutex_lock(&filter_mutex);
276 __filter_free_subsystem_preds(system);
277 mutex_unlock(&filter_mutex);
278}
279
280static int filter_add_pred_fn(struct ftrace_event_call *call,
281 struct filter_pred *pred,
282 filter_pred_fn_t fn)
7ce7e424 283{
0a19e53c 284 int idx, err;
7ce7e424 285
0a19e53c 286 if (call->n_preds && !pred->compound)
ac1adc55 287 __filter_disable_preds(call);
7ce7e424 288
0a19e53c
TZ
289 if (call->n_preds == MAX_FILTER_PRED)
290 return -ENOSPC;
7ce7e424 291
0a19e53c
TZ
292 idx = call->n_preds;
293 filter_clear_pred(call->preds[idx]);
294 err = filter_set_pred(call->preds[idx], pred, fn);
295 if (err)
296 return err;
297
298 call->n_preds++;
7ce7e424 299
0a19e53c 300 return 0;
7ce7e424
TZ
301}
302
303static int is_string_field(const char *type)
304{
305 if (strchr(type, '[') && strstr(type, "char"))
306 return 1;
307
308 return 0;
309}
310
ac1adc55
TZ
311static int __filter_add_pred(struct ftrace_event_call *call,
312 struct filter_pred *pred)
7ce7e424
TZ
313{
314 struct ftrace_event_field *field;
0a19e53c 315 filter_pred_fn_t fn;
f66578a7 316 unsigned long long val;
7ce7e424
TZ
317
318 field = find_event_field(call, pred->field_name);
319 if (!field)
320 return -EINVAL;
321
0a19e53c 322 pred->fn = filter_pred_none;
7ce7e424
TZ
323 pred->offset = field->offset;
324
325 if (is_string_field(field->type)) {
0a19e53c 326 fn = filter_pred_string;
7ce7e424 327 pred->str_len = field->size;
ac1adc55 328 return filter_add_pred_fn(call, pred, fn);
9f58a159 329 } else {
f66578a7 330 if (strict_strtoull(pred->str_val, 0, &val))
9f58a159 331 return -EINVAL;
f66578a7 332 pred->val = val;
7ce7e424
TZ
333 }
334
335 switch (field->size) {
336 case 8:
0a19e53c 337 fn = filter_pred_64;
7ce7e424
TZ
338 break;
339 case 4:
0a19e53c 340 fn = filter_pred_32;
7ce7e424
TZ
341 break;
342 case 2:
0a19e53c 343 fn = filter_pred_16;
7ce7e424
TZ
344 break;
345 case 1:
0a19e53c 346 fn = filter_pred_8;
7ce7e424
TZ
347 break;
348 default:
349 return -EINVAL;
350 }
351
ac1adc55
TZ
352 return filter_add_pred_fn(call, pred, fn);
353}
354
355int filter_add_pred(struct ftrace_event_call *call, struct filter_pred *pred)
356{
357 int err;
358
359 mutex_lock(&filter_mutex);
360 err = __filter_add_pred(call, pred);
361 mutex_unlock(&filter_mutex);
362
363 return err;
cfb180f3
TZ
364}
365
366int filter_add_subsystem_pred(struct event_subsystem *system,
367 struct filter_pred *pred)
368{
a59fd602 369 struct ftrace_event_call *call;
cfb180f3 370
ac1adc55
TZ
371 mutex_lock(&filter_mutex);
372
0a19e53c 373 if (system->n_preds && !pred->compound)
ac1adc55 374 __filter_free_subsystem_preds(system);
cfb180f3 375
0a19e53c 376 if (!system->n_preds) {
cfb180f3
TZ
377 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
378 GFP_KERNEL);
ac1adc55
TZ
379 if (!system->preds) {
380 mutex_unlock(&filter_mutex);
cfb180f3 381 return -ENOMEM;
ac1adc55 382 }
cfb180f3
TZ
383 }
384
ac1adc55
TZ
385 if (system->n_preds == MAX_FILTER_PRED) {
386 mutex_unlock(&filter_mutex);
44e9c8b7 387 return -ENOSPC;
ac1adc55 388 }
c4cff064 389
0a19e53c 390 system->preds[system->n_preds] = pred;
ac1adc55 391 system->n_preds++;
0a19e53c 392
a59fd602 393 list_for_each_entry(call, &ftrace_events, list) {
c4cff064
TZ
394 int err;
395
e1112b4d 396 if (!call->define_fields)
cfb180f3
TZ
397 continue;
398
c4cff064
TZ
399 if (strcmp(call->system, system->name))
400 continue;
401
ac1adc55 402 err = __filter_add_pred(call, pred);
0a19e53c
TZ
403 if (err == -ENOMEM) {
404 system->preds[system->n_preds] = NULL;
ac1adc55
TZ
405 system->n_preds--;
406 mutex_unlock(&filter_mutex);
0a19e53c
TZ
407 return err;
408 }
cfb180f3
TZ
409 }
410
ac1adc55 411 mutex_unlock(&filter_mutex);
c4cff064 412
0a19e53c 413 return 0;
cfb180f3
TZ
414}
415
f66578a7
LZ
416/*
417 * The filter format can be
418 * - 0, which means remove all filter preds
419 * - [||/&&] <field> ==/!= <val>
420 */
7ce7e424
TZ
421int filter_parse(char **pbuf, struct filter_pred *pred)
422{
f66578a7 423 char *tok, *val_str = NULL;
7ce7e424
TZ
424 int tok_n = 0;
425
7ce7e424
TZ
426 while ((tok = strsep(pbuf, " \n"))) {
427 if (tok_n == 0) {
428 if (!strcmp(tok, "0")) {
429 pred->clear = 1;
430 return 0;
431 } else if (!strcmp(tok, "&&")) {
432 pred->or = 0;
433 pred->compound = 1;
434 } else if (!strcmp(tok, "||")) {
435 pred->or = 1;
436 pred->compound = 1;
437 } else
438 pred->field_name = tok;
439 tok_n = 1;
440 continue;
441 }
442 if (tok_n == 1) {
443 if (!pred->field_name)
444 pred->field_name = tok;
445 else if (!strcmp(tok, "!="))
446 pred->not = 1;
447 else if (!strcmp(tok, "=="))
448 pred->not = 0;
449 else {
450 pred->field_name = NULL;
451 return -EINVAL;
452 }
453 tok_n = 2;
454 continue;
455 }
456 if (tok_n == 2) {
457 if (pred->compound) {
458 if (!strcmp(tok, "!="))
459 pred->not = 1;
460 else if (!strcmp(tok, "=="))
461 pred->not = 0;
462 else {
463 pred->field_name = NULL;
464 return -EINVAL;
465 }
466 } else {
467 val_str = tok;
468 break; /* done */
469 }
470 tok_n = 3;
471 continue;
472 }
473 if (tok_n == 3) {
474 val_str = tok;
475 break; /* done */
476 }
477 }
478
0a19e53c
TZ
479 if (!val_str || !strlen(val_str)
480 || strlen(val_str) >= MAX_FILTER_STR_VAL) {
bcabd91c
LZ
481 pred->field_name = NULL;
482 return -EINVAL;
483 }
484
f66578a7
LZ
485 strcpy(pred->str_val, val_str);
486 pred->str_len = strlen(val_str);
487
7ce7e424
TZ
488 pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
489 if (!pred->field_name)
490 return -ENOMEM;
491
7ce7e424
TZ
492 return 0;
493}
494
495
This page took 0.06769 seconds and 5 git commands to generate.