tracing/filters: use trace_seq_printf() to print filters
[deliverable/linux.git] / 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 pred->fn = filter_pred_string;
241 pred->str_len = field->size;
242 return __filter_add_pred(call, pred);
243 }
244
245 switch (field->size) {
246 case 8:
247 pred->fn = filter_pred_64;
248 break;
249 case 4:
250 pred->fn = filter_pred_32;
251 break;
252 case 2:
253 pred->fn = filter_pred_16;
254 break;
255 case 1:
256 pred->fn = filter_pred_8;
257 break;
258 default:
259 return -EINVAL;
260 }
261
262 return __filter_add_pred(call, pred);
263 }
264
265 static struct filter_pred *copy_pred(struct filter_pred *pred)
266 {
267 struct filter_pred *new_pred = kmalloc(sizeof(*pred), GFP_KERNEL);
268 if (!new_pred)
269 return NULL;
270
271 memcpy(new_pred, pred, sizeof(*pred));
272
273 if (pred->field_name) {
274 new_pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
275 if (!new_pred->field_name) {
276 kfree(new_pred);
277 return NULL;
278 }
279 }
280
281 if (pred->str_val) {
282 new_pred->str_val = kstrdup(pred->str_val, GFP_KERNEL);
283 if (!new_pred->str_val) {
284 filter_free_pred(new_pred);
285 return NULL;
286 }
287 }
288
289 return new_pred;
290 }
291
292 int filter_add_subsystem_pred(struct event_subsystem *system,
293 struct filter_pred *pred)
294 {
295 struct ftrace_event_call *call = __start_ftrace_events;
296 struct filter_pred *event_pred;
297 int i;
298
299 if (system->preds && !pred->compound)
300 filter_free_subsystem_preds(system);
301
302 if (!system->preds) {
303 system->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred),
304 GFP_KERNEL);
305 if (!system->preds)
306 return -ENOMEM;
307 }
308
309 for (i = 0; i < MAX_FILTER_PRED; i++) {
310 if (!system->preds[i]) {
311 system->preds[i] = pred;
312 break;
313 }
314 }
315
316 if (i == MAX_FILTER_PRED)
317 return -EINVAL;
318
319 events_for_each(call) {
320 int err;
321
322 if (!call->name || !call->regfunc)
323 continue;
324
325 if (strcmp(call->system, system->name))
326 continue;
327
328 if (!find_event_field(call, pred->field_name))
329 continue;
330
331 event_pred = copy_pred(pred);
332 if (!event_pred)
333 goto oom;
334
335 err = filter_add_pred(call, event_pred);
336 if (err)
337 filter_free_pred(event_pred);
338 if (err == -ENOMEM)
339 goto oom;
340 }
341
342 return 0;
343
344 oom:
345 system->preds[i] = NULL;
346 return -ENOMEM;
347 }
348
349 int filter_parse(char **pbuf, struct filter_pred *pred)
350 {
351 char *tmp, *tok, *val_str = NULL;
352 int tok_n = 0;
353
354 /* field ==/!= number, or/and field ==/!= number, number */
355 while ((tok = strsep(pbuf, " \n"))) {
356 if (tok_n == 0) {
357 if (!strcmp(tok, "0")) {
358 pred->clear = 1;
359 return 0;
360 } else if (!strcmp(tok, "&&")) {
361 pred->or = 0;
362 pred->compound = 1;
363 } else if (!strcmp(tok, "||")) {
364 pred->or = 1;
365 pred->compound = 1;
366 } else
367 pred->field_name = tok;
368 tok_n = 1;
369 continue;
370 }
371 if (tok_n == 1) {
372 if (!pred->field_name)
373 pred->field_name = tok;
374 else if (!strcmp(tok, "!="))
375 pred->not = 1;
376 else if (!strcmp(tok, "=="))
377 pred->not = 0;
378 else {
379 pred->field_name = NULL;
380 return -EINVAL;
381 }
382 tok_n = 2;
383 continue;
384 }
385 if (tok_n == 2) {
386 if (pred->compound) {
387 if (!strcmp(tok, "!="))
388 pred->not = 1;
389 else if (!strcmp(tok, "=="))
390 pred->not = 0;
391 else {
392 pred->field_name = NULL;
393 return -EINVAL;
394 }
395 } else {
396 val_str = tok;
397 break; /* done */
398 }
399 tok_n = 3;
400 continue;
401 }
402 if (tok_n == 3) {
403 val_str = tok;
404 break; /* done */
405 }
406 }
407
408 pred->field_name = kstrdup(pred->field_name, GFP_KERNEL);
409 if (!pred->field_name)
410 return -ENOMEM;
411
412 pred->val = simple_strtoull(val_str, &tmp, 10);
413 if (tmp == val_str) {
414 pred->str_val = kstrdup(val_str, GFP_KERNEL);
415 if (!pred->str_val)
416 return -ENOMEM;
417 }
418
419 return 0;
420 }
421
422
This page took 0.051498 seconds and 5 git commands to generate.