aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--parse-events.c48
-rw-r--r--parse-events.h116
-rw-r--r--parse-filter.c847
-rw-r--r--trace-cmd.c3
-rw-r--r--trace-read.c69
6 files changed, 1068 insertions, 17 deletions
diff --git a/Makefile b/Makefile
index 3596d1e..20e7af2 100644
--- a/Makefile
+++ b/Makefile
@@ -149,7 +149,7 @@ TRACE_VIEW_MAIN_OBJS = trace-view-main.o $(TRACE_VIEW_OBJS)
149TRACE_GRAPH_MAIN_OBJS = trace-graph-main.o $(TRACE_GRAPH_OBJS) 149TRACE_GRAPH_MAIN_OBJS = trace-graph-main.o $(TRACE_GRAPH_OBJS)
150KERNEL_SHARK_OBJS = $(TRACE_VIEW_OBJS) $(TRACE_GRAPH_OBJS) kernel-shark.o 150KERNEL_SHARK_OBJS = $(TRACE_VIEW_OBJS) $(TRACE_GRAPH_OBJS) kernel-shark.o
151 151
152PEVENT_LIB_OBJS = parse-events.o trace-seq.o 152PEVENT_LIB_OBJS = parse-events.o trace-seq.o parse-filter.o
153TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \ 153TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \
154 trace-output.o trace-record.o 154 trace-output.o trace-record.o
155 155
diff --git a/parse-events.c b/parse-events.c
index 1592fa3..b29a8d5 100644
--- a/parse-events.c
+++ b/parse-events.c
@@ -44,6 +44,19 @@ static void init_input_buf(const char *buf, unsigned long long size)
44 input_buf_ptr = 0; 44 input_buf_ptr = 0;
45} 45}
46 46
47/**
48 * pevent_buffer_init - init buffer for parsing
49 * @buf: buffer to parse
50 * @size: the size of the buffer
51 *
52 * For use with pevent_read_token(), this initializes the internal
53 * buffer that pevent_read_token() will parse.
54 */
55void pevent_buffer_init(const char *buf, unsigned long long size)
56{
57 init_input_buf(buf, size);
58}
59
47void breakpoint(void) 60void breakpoint(void)
48{ 61{
49 static int x; 62 static int x;
@@ -551,18 +564,6 @@ static struct event_format *alloc_event(void)
551 return event; 564 return event;
552} 565}
553 566
554enum event_type {
555 EVENT_ERROR,
556 EVENT_NONE,
557 EVENT_SPACE,
558 EVENT_NEWLINE,
559 EVENT_OP,
560 EVENT_DELIM,
561 EVENT_ITEM,
562 EVENT_DQUOTE,
563 EVENT_SQUOTE,
564};
565
566static void add_event(struct pevent *pevent, struct event_format *event) 567static void add_event(struct pevent *pevent, struct event_format *event)
567{ 568{
568 int i; 569 int i;
@@ -914,6 +915,29 @@ static enum event_type read_token(char **tok)
914 return EVENT_NONE; 915 return EVENT_NONE;
915} 916}
916 917
918/**
919 * pevent_read_token - access to utilites to use the pevent parser
920 * @tok: The token to return
921 *
922 * This will parse tokens from the string given by
923 * pevent_init_data().
924 *
925 * Returns the token type.
926 */
927enum event_type pevent_read_token(char **tok)
928{
929 return read_token(tok);
930}
931
932/**
933 * pevent_free_token - free a token returned by pevent_read_token
934 * @token: the token to free
935 */
936void pevent_free_token(char *token)
937{
938 free_token(token);
939}
940
917/* no newline */ 941/* no newline */
918static enum event_type read_token_item(char **tok) 942static enum event_type read_token_item(char **tok)
919{ 943{
diff --git a/parse-events.h b/parse-events.h
index 879da4c..cc5af58 100644
--- a/parse-events.h
+++ b/parse-events.h
@@ -110,7 +110,7 @@ enum format_flags {
110 110
111struct format_field { 111struct format_field {
112 struct format_field *next; 112 struct format_field *next;
113 struct event_format *event; 113 struct event_format *event;
114 char *type; 114 char *type;
115 char *name; 115 char *name;
116 int offset; 116 int offset;
@@ -240,6 +240,18 @@ enum event_sort_type {
240 EVENT_SORT_SYSTEM, 240 EVENT_SORT_SYSTEM,
241}; 241};
242 242
243enum event_type {
244 EVENT_ERROR,
245 EVENT_NONE,
246 EVENT_SPACE,
247 EVENT_NEWLINE,
248 EVENT_OP,
249 EVENT_DELIM,
250 EVENT_ITEM,
251 EVENT_DQUOTE,
252 EVENT_SQUOTE,
253};
254
243struct cmdline; 255struct cmdline;
244struct cmdline_list; 256struct cmdline_list;
245struct func_map; 257struct func_map;
@@ -469,9 +481,111 @@ void pevent_free(struct pevent *pevent);
469void pevent_ref(struct pevent *pevent); 481void pevent_ref(struct pevent *pevent);
470void pevent_unref(struct pevent *pevent); 482void pevent_unref(struct pevent *pevent);
471 483
484/* access to the internal parser */
485void pevent_buffer_init(const char *buf, unsigned long long size);
486enum event_type pevent_read_token(char **tok);
487void pevent_free_token(char *token);
488
472/* for debugging */ 489/* for debugging */
473void pevent_print_funcs(struct pevent *pevent); 490void pevent_print_funcs(struct pevent *pevent);
474void pevent_print_printk(struct pevent *pevent); 491void pevent_print_printk(struct pevent *pevent);
475 492
493/* ----------------------- filtering ----------------------- */
494
495enum filter_boolean_type {
496 FILTER_FALSE,
497 FILTER_TRUE,
498};
499
500enum filter_op_type {
501 FILTER_OP_AND = 1,
502 FILTER_OP_OR,
503 FILTER_OP_NOT,
504};
505
506enum filter_cmp_type {
507 FILTER_CMP_NONE,
508 FILTER_CMP_EQ,
509 FILTER_CMP_NE,
510 FILTER_CMP_GT,
511 FILTER_CMP_LT,
512 FILTER_CMP_GE,
513 FILTER_CMP_LE,
514 FILTER_CMP_MATCH,
515 FILTER_CMP_NOT_MATCH,
516 FILTER_CMP_CONTAIN,
517 FILTER_CMP_NOT_CONTAIN,
518};
519
520enum filter_arg_type {
521 FILTER_ARG_NONE,
522 FILTER_ARG_BOOLEAN,
523 FILTER_ARG_OP,
524 FILTER_ARG_NUM,
525 FILTER_ARG_STR,
526};
527
528struct fliter_arg;
529
530struct filter_arg_boolean {
531 enum filter_boolean_type value;
532};
533
534struct filter_arg_op {
535 enum filter_op_type type;
536 struct filter_arg *left;
537 struct filter_arg *right;
538};
539
540struct filter_arg_num {
541 enum filter_cmp_type type;
542 struct format_field *field;
543 unsigned long long val;
544};
545
546struct filter_arg_str {
547 enum filter_cmp_type type;
548 struct format_field *field;
549 char *val;
550};
551
552struct filter_arg {
553 enum filter_arg_type type;
554 union {
555 struct filter_arg_boolean bool;
556 struct filter_arg_op op;
557 struct filter_arg_num num;
558 struct filter_arg_str str;
559 };
560};
561
562struct filter_type {
563 int event_id;
564 struct event_format *event;
565 struct filter_arg *filter;
566};
567
568struct event_filter {
569 struct pevent *pevent;
570 int filters;
571 struct filter_type *event_filters;
572};
573
574struct event_filter *pevent_filter_alloc(struct pevent *pevent);
575
576#define FILTER_NONE -2
577#define FILTER_NOEXIST -1
578#define FILTER_MISS 0
579#define FILTER_MATCH 1
580
581int pevent_filter_add_filter_str(struct event_filter *filter,
582 const char *filter_str,
583 char **error_str);
584
585
586int pevent_filter_match(struct event_filter *filter,
587 struct record *record);
588
589void pevent_filter_free(struct event_filter *filter);
476 590
477#endif /* _PARSE_EVENTS_H */ 591#endif /* _PARSE_EVENTS_H */
diff --git a/parse-filter.c b/parse-filter.c
new file mode 100644
index 0000000..156b7e9
--- /dev/null
+++ b/parse-filter.c
@@ -0,0 +1,847 @@
1/*
2 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <stdarg.h>
25#include <ctype.h>
26#include <errno.h>
27
28#include "parse-events.h"
29
30struct event_list {
31 struct event_list *next;
32 struct event_format *event;
33};
34
35#define MAX_ERR_STR_SIZE 256
36
37static void show_error(char **error_str, const char *fmt, ...)
38{
39 va_list ap;
40
41 if (!error_str)
42 return;
43
44 *error_str = malloc_or_die(MAX_ERR_STR_SIZE);
45
46 va_start(ap, fmt);
47 vsnprintf(*error_str, MAX_ERR_STR_SIZE, fmt, ap);
48 va_end(ap);
49}
50
51static void free_token(char *token)
52{
53 pevent_free_token(token);
54}
55
56static enum event_type read_token(char **tok)
57{
58 enum event_type type;
59 char *token = NULL;
60
61 do {
62 free_token(token);
63 type = pevent_read_token(&token);
64 } while (type == EVENT_NEWLINE || type == EVENT_SPACE);
65
66 *tok = token;
67 return type;
68}
69
70static int filter_cmp(const void *a, const void *b)
71{
72 const struct filter_type *ea = a;
73 const struct filter_type *eb = b;
74
75 if (ea->event_id < eb->event_id)
76 return -1;
77
78 if (ea->event_id > eb->event_id)
79 return 1;
80
81 return 0;
82}
83
84static struct filter_type *
85find_filter_type(struct event_filter *filter, int id)
86{
87 struct filter_type *filter_type;
88 struct filter_type key;
89
90 key.event_id = id;
91
92 filter_type = bsearch(&key, filter->event_filters,
93 filter->filters,
94 sizeof(*filter->event_filters),
95 filter_cmp);
96
97 return filter_type;
98}
99
100static struct filter_type *
101add_filter_type(struct event_filter *filter, int id)
102{
103 struct filter_type *filter_type;
104 int i;
105
106 filter_type = find_filter_type(filter, id);
107 if (filter_type)
108 return filter_type;
109
110 if (!filter->filters)
111 filter->event_filters =
112 malloc_or_die(sizeof(*filter->event_filters));
113 else {
114 filter->event_filters =
115 realloc(filter->event_filters,
116 sizeof(*filter->event_filters) *
117 (filter->filters + 1));
118 if (!filter->event_filters)
119 die("Could not allocate filter");
120 }
121
122 for (i = 0; i < filter->filters; i++) {
123 if (filter->event_filters[i].event_id > id)
124 break;
125 }
126
127 if (i < filter->filters)
128 memmove(&filter->event_filters[i+1],
129 &filter->event_filters[i],
130 sizeof(*filter->event_filters) *
131 (filter->filters - i));
132
133 filter_type = &filter->event_filters[i];
134 filter_type->event_id = id;
135 filter_type->event = pevent_find_event(filter->pevent, id);
136 filter_type->filter = NULL;
137
138 filter->filters++;
139
140 return filter_type;
141}
142
143/**
144 * pevent_filter_alloc - create a new event filter
145 * @pevent: The pevent that this filter is associated with
146 */
147struct event_filter *pevent_filter_alloc(struct pevent *pevent)
148{
149 struct event_filter *filter;
150
151 filter = malloc_or_die(sizeof(*filter));
152 memset(filter, 0, sizeof(*filter));
153 filter->pevent = pevent;
154 pevent_ref(pevent);
155
156 return filter;
157}
158
159static struct filter_arg *allocate_arg(void)
160{
161 struct filter_arg *arg;
162
163 arg = malloc_or_die(sizeof(*arg));
164 memset(arg, 0, sizeof(*arg));
165
166 return arg;
167}
168
169static void free_arg(struct filter_arg *arg)
170{
171 if (!arg)
172 return;
173
174 switch (arg->type) {
175 case FILTER_ARG_NONE:
176 case FILTER_ARG_BOOLEAN:
177 case FILTER_ARG_NUM:
178 break;
179
180 case FILTER_ARG_STR:
181 free(arg->str.val);
182 break;
183
184 case FILTER_ARG_OP:
185 free_arg(arg->op.left);
186 free_arg(arg->op.right);
187 default:
188 break;
189 }
190
191 free(arg);
192}
193
194static int
195find_event(struct pevent *pevent, struct event_list **events,
196 char *sys_name, char *event_name)
197{
198 struct event_format *event;
199 struct event_list *list;
200
201 event = pevent_find_event_by_name(pevent, sys_name, event_name);
202 if (!event)
203 return -1;
204
205 list = malloc_or_die(sizeof(*list));
206 list->next = *events;
207 *events = list;
208 list->event = event;
209
210 return 0;
211}
212
213static void free_events(struct event_list *events)
214{
215 struct event_list *event;
216
217 while (events) {
218 event = events;
219 events = events->next;
220 free(event);
221 }
222}
223
224static int process_valid_field(struct filter_arg *arg,
225 struct format_field *field,
226 enum filter_cmp_type op_type,
227 enum event_type type,
228 char *val,
229 char **error_str)
230{
231 switch (type) {
232
233 case EVENT_SQUOTE:
234 /* treat this as a character if string is of length 1? */
235 if (strlen(val) == 1)
236 goto as_int;
237 /* fall through */
238
239 case EVENT_DQUOTE:
240 /* right now only allow match */
241 switch (op_type) {
242 case FILTER_CMP_EQ:
243 op_type = FILTER_CMP_MATCH;
244 break;
245 case FILTER_CMP_NE:
246 op_type = FILTER_CMP_NOT_MATCH;
247 break;
248
249 default:
250 show_error(error_str,
251 "Op not allowed with string");
252 return -1;
253 }
254 arg->type = FILTER_ARG_STR;
255 arg->str.field = field;
256 arg->str.type = op_type;
257 arg->str.val = strdup(val);
258 if (!arg->str.val)
259 die("Can't allocate arg value");
260 break;
261 case EVENT_ITEM:
262 as_int:
263 arg->type = FILTER_ARG_NUM;
264 arg->num.field = field;
265 arg->num.type = op_type;
266 arg->num.val = strtoll(val, NULL, 0);
267 break;
268
269 default:
270 /* Can't happen */
271 return -1;
272 }
273
274 return 0;
275}
276
277static enum event_type
278process_filter(struct event_format *event, struct filter_arg **parg,
279 char **tok, char **error_str, int cont);
280
281static enum event_type
282process_paren(struct event_format *event, struct filter_arg **parg,
283 char **tok, char **error_str, int cont);
284
285static enum event_type
286process_not(struct event_format *event, struct filter_arg **parg,
287 char **tok, char **error_str, int cont);
288
289static enum event_type
290process_token(struct event_format *event, struct filter_arg **parg,
291 char **tok, char **error_str, int cont)
292{
293 enum event_type type;
294 char *token;
295
296 *tok = NULL;
297 *parg = NULL;
298
299 type = read_token(&token);
300
301 if (type == EVENT_ITEM) {
302 type = process_filter(event, parg, &token, error_str, cont);
303
304 } else if (type == EVENT_DELIM && strcmp(token, "(") == 0) {
305 free_token(token);
306 type = process_paren(event, parg, &token, error_str, cont);
307
308 } else if (type == EVENT_OP && strcmp(token, "!") == 0) {
309 type = process_not(event, parg, &token, error_str, cont);
310 }
311
312 if (type == EVENT_ERROR) {
313 free_token(token);
314 free_arg(*parg);
315 *parg = NULL;
316 return EVENT_ERROR;
317 }
318
319 *tok = token;
320 return type;
321}
322
323static enum event_type
324process_op(struct event_format *event, struct filter_arg *larg,
325 struct filter_arg **parg, char **tok, char **error_str)
326{
327 enum event_type type;
328 struct filter_arg *arg;
329
330 arg = allocate_arg();
331 arg->type = FILTER_ARG_OP;
332 arg->op.left = larg;
333
334 /* Can only be called with '&&' or '||' */
335 arg->op.type = strcmp(*tok, "&&") == 0 ?
336 FILTER_OP_AND : FILTER_OP_OR;
337
338 free_token(*tok);
339
340 type = process_token(event, &arg->op.right, tok, error_str, 1);
341 if (type == EVENT_ERROR)
342 free_arg(arg);
343
344 *parg = arg;
345
346 return type;
347}
348
349static enum event_type
350process_filter(struct event_format *event, struct filter_arg **parg,
351 char **tok, char **error_str, int cont)
352{
353 struct format_field *field;
354 enum filter_cmp_type etype;
355 struct filter_arg *arg;
356 enum event_type type;
357 char *field_name;
358 char *token;
359 char *op;
360 int ret;
361
362 *parg = NULL;
363
364 field_name = *tok;
365 *tok = NULL;
366
367 type = read_token(&token);
368 if (type != EVENT_OP) {
369 if (type == EVENT_NONE)
370 show_error(error_str,
371 "Expected OP but found end of filter after %s",
372 field_name);
373 else
374 show_error(error_str,
375 "Expected OP but found %s after %s",
376 token, field_name);
377 free_token(field_name);
378 free_token(token);
379 return EVENT_ERROR;
380 }
381
382 if (strcmp(token, "==") == 0) {
383 etype = FILTER_CMP_EQ;
384 } else if (strcmp(token, "!=") == 0) {
385 etype = FILTER_CMP_NE;
386 } else if (strcmp(token, "<") == 0) {
387 etype = FILTER_CMP_LT;
388 } else if (strcmp(token, ">") == 0) {
389 etype = FILTER_CMP_GT;
390 } else if (strcmp(token, "<=") == 0) {
391 etype = FILTER_CMP_LE;
392 } else if (strcmp(token, ">=") == 0) {
393 etype = FILTER_CMP_GE;
394 } else {
395 show_error(error_str,
396 "Unknown op '%s' after '%s'",
397 token, field_name);
398 free_token(field_name);
399 free_token(token);
400 return EVENT_ERROR;
401 }
402 op = token;
403
404 type = read_token(&token);
405 if (type != EVENT_ITEM && type != EVENT_SQUOTE && type != EVENT_DQUOTE) {
406 show_error(error_str,
407 "Expected an item after '%s %s' instead of %s",
408 field_name, op, token);
409 free_token(field_name);
410 free_token(op);
411 free_token(token);
412 return EVENT_ERROR;
413 }
414 free_token(op);
415
416 field = pevent_find_field(event, field_name);
417 free_token(field_name);
418
419 arg = allocate_arg();
420
421 if (field) {
422 ret = process_valid_field(arg, field, etype, type, token, error_str);
423 if (ret < 0) {
424 free_arg(arg);
425 return EVENT_ERROR;
426 }
427 } else {
428 /*
429 * When an event does not contain a field in the
430 * filter, just make it false.
431 */
432 arg->type = FILTER_ARG_BOOLEAN;
433 arg->bool.value = FILTER_FALSE;
434 }
435
436 free_token(token);
437
438 type = read_token(tok);
439
440 if (cont && type == EVENT_OP &&
441 (strcmp(*tok, "&&") == 0 || strcmp(*tok, "||") == 0)) {
442 /* continue */;
443 type = process_op(event, arg, parg, tok, error_str);
444 } else
445 *parg = arg;
446
447 return type;
448}
449
450static enum event_type
451process_paren(struct event_format *event, struct filter_arg **parg,
452 char **tok, char **error_str, int cont)
453{
454 struct filter_arg *arg;
455 enum event_type type;
456
457 *parg = NULL;
458
459 type = process_token(event, &arg, tok, error_str, 1);
460 if (type == EVENT_ERROR) {
461 free_arg(arg);
462 return type;
463 }
464 if (type != EVENT_DELIM || strcmp(*tok, ")") != 0) {
465 if (*tok)
466 show_error(error_str,
467 "Expected ')' but found %s", *tok);
468 else
469 show_error(error_str,
470 "Unexpected end of filter; Expected ')'");
471 free_token(*tok);
472 *tok = NULL;
473 free_arg(arg);
474 return EVENT_ERROR;
475 }
476 free_token(*tok);
477
478 type = read_token(tok);
479
480 if (cont && type == EVENT_OP &&
481 (strcmp(*tok, "&&") == 0 || strcmp(*tok, "||") == 0)) {
482 /* continue */;
483 type = process_op(event, arg, parg, tok, error_str);
484 } else
485 *parg = arg;
486
487 return type;
488}
489
490static enum event_type
491process_not(struct event_format *event, struct filter_arg **parg,
492 char **tok, char **error_str, int cont)
493{
494 struct filter_arg *arg;
495 enum event_type type;
496
497 arg = allocate_arg();
498 arg->type = FILTER_ARG_OP;
499 arg->op.type = FILTER_OP_NOT;
500
501 arg->op.left = NULL;
502 type = process_token(event, &arg->op.right, tok, error_str, 0);
503 if (type == EVENT_ERROR) {
504 free_arg(arg);
505 *parg = NULL;
506 free_token(*tok);
507 *tok = NULL;
508 return EVENT_ERROR;
509 }
510
511 if (cont && type == EVENT_OP &&
512 (strcmp(*tok, "&&") == 0 || strcmp(*tok, "||") == 0)) {
513 /* continue */;
514 type = process_op(event, arg, parg, tok, error_str);
515 } else
516 *parg = arg;
517
518 return type;
519}
520
521static int filter_event(struct event_filter *filter,
522 struct event_format *event,
523 const char *filter_str, char **error_str)
524{
525 struct filter_type *filter_type;
526 enum event_type type;
527 struct filter_arg *arg;
528 char *token;
529
530 pevent_buffer_init(filter_str, strlen(filter_str));
531
532 type = process_token(event, &arg, &token, error_str, 1);
533
534 if (type == EVENT_ERROR)
535 return -1;
536
537 if (type != EVENT_NONE) {
538 show_error(error_str,
539 "Expected end where %s was found",
540 token);
541 free_token(token);
542 free_arg(arg);
543 return -1;
544 }
545
546 filter_type = add_filter_type(filter, event->id);
547 if (filter_type->filter)
548 free_arg(filter_type->filter);
549 filter_type->filter = arg;
550
551 return 0;
552}
553
554/**
555 * pevent_filter_add_filter_str - add a new filter
556 * @filter: the event filter to add to
557 * @filter_str: the filter string that contains the filter
558 * @error_str: string containing reason for failed filter
559 *
560 * Returns 0 if the filter was successfully added
561 * -1 if there was an error.
562 *
563 * On error, if @error_str points to a string pointer,
564 * it is set to the reason that the filter failed.
565 * This string must be freed with "free".
566 */
567int pevent_filter_add_filter_str(struct event_filter *filter,
568 const char *filter_str,
569 char **error_str)
570{
571 struct pevent *pevent = filter->pevent;
572 struct event_list *event;
573 struct event_list *events = NULL;
574 enum event_type type;
575 const char *filter_start;
576 char *event_name = NULL;
577 char *sys_name = NULL;
578 char *token;
579 int rtn = 0;
580 int ret;
581
582 if (error_str)
583 *error_str = NULL;
584
585 filter_start = strchr(filter_str, ':');
586 if (!filter_start) {
587 show_error(error_str, "No filter found");
588 return -1;
589 }
590
591 pevent_buffer_init(filter_str, filter_start - filter_str);
592
593 again:
594 type = read_token(&token);
595 if (type != EVENT_ITEM) {
596 show_error(error_str, "Expected an event name but got %s",
597 token);
598 free_token(token);
599 return -1;
600 }
601
602 sys_name = token;
603 type = read_token(&token);
604 if (type == EVENT_OP && strcmp(token, ".") == 0) {
605 /* this is of "system.event" format */
606 free_token(token);
607 type = read_token(&token);
608 if (type != EVENT_ITEM) {
609 if (token)
610 show_error(error_str,
611 "Expected an event after '%s.' and before %s",
612 sys_name, token);
613 else
614 show_error(error_str,
615 "Expected an event after '%s.'",
616 sys_name);
617 goto out_err;
618 }
619 event_name = token;
620 type = read_token(&token);
621 } else
622 event_name = NULL;
623
624 /* Find this event */
625 ret = find_event(pevent, &events, sys_name, event_name);
626 if (ret < 0) {
627 if (event_name)
628 show_error(error_str,
629 "No event found under '%s.%s'",
630 sys_name, event_name);
631 else
632 show_error(error_str,
633 "No event found under '%s'",
634 sys_name);
635 goto out_err;
636 }
637
638 free_token(sys_name);
639 free_token(event_name);
640 sys_name = NULL;
641 event_name = NULL;
642
643 if (type == EVENT_DELIM && strcmp(token, ",")) {
644 /* This filter is for more than one event */
645 free_token(token);
646 goto again;
647 }
648
649 /* this should be the end of parsing events */
650 if (type != EVENT_NONE) {
651 free_events(events);
652 show_error(error_str,
653 "expected ':' after %s", token);
654 free_token(token);
655 return -1;
656 }
657
658 /* filter starts here */
659 for (event = events; event; event = event->next) {
660 ret = filter_event(filter, event->event, filter_start + 1,
661 error_str);
662 /* Failures are returned if a parse error happened */
663 if (ret < 0)
664 rtn = ret;
665 }
666
667 free_events(events);
668
669 return rtn;
670
671 out_err:
672 free_token(event_name);
673 free_token(sys_name);
674 free_token(token);
675 free_events(events);
676 return -1;
677}
678
679static void free_filter_type(struct filter_type *filter_type)
680{
681 free_arg(filter_type->filter);
682}
683
684void pevent_filter_free(struct event_filter *filter)
685{
686 int i;
687
688 pevent_unref(filter->pevent);
689
690 for (i = 0; i < filter->filters; i++)
691 free_filter_type(&filter->event_filters[i]);
692
693 free(filter);
694}
695
696static int test_filter(struct event_format *event,
697 struct filter_arg *arg, struct record *record);
698
699static unsigned long long
700get_value(struct format_field *field, struct record *record)
701{
702 unsigned long long val;
703
704 pevent_read_number_field(field, record->data, &val);
705
706 if (!(field->flags & FIELD_IS_SIGNED))
707 return val;
708
709 switch (field->size) {
710 case 1:
711 return (char)val;
712 case 2:
713 return (short)val;
714 case 4:
715 return (int)val;
716 case 8:
717 return (long long)val;
718 }
719 return val;
720}
721
722static int test_num(struct event_format *event,
723 struct filter_arg *arg, struct record *record)
724{
725 unsigned long long val;
726
727 val = get_value(arg->num.field, record);
728
729 switch (arg->num.type) {
730 case FILTER_CMP_EQ:
731 return val == arg->num.val;
732
733 case FILTER_CMP_NE:
734 return val != arg->num.val;
735
736 case FILTER_CMP_GT:
737 return val > arg->num.val;
738
739 case FILTER_CMP_LT:
740 return val < arg->num.val;
741
742 case FILTER_CMP_GE:
743 return val >= arg->num.val;
744
745 case FILTER_CMP_LE:
746 return val <= arg->num.val;
747
748 default:
749 /* ?? */
750 return 0;
751 }
752}
753
754static int test_str(struct event_format *event,
755 struct filter_arg *arg, struct record *record)
756{
757 const char *val = record->data + arg->str.field->offset;
758
759 switch (arg->str.type) {
760 case FILTER_CMP_MATCH:
761 return strncmp(val, arg->str.val, arg->str.field->size) == 0;
762
763 case FILTER_CMP_NOT_MATCH:
764 return strncmp(val, arg->str.val, arg->str.field->size) != 0;
765
766 default:
767 /* ?? */
768 return 0;
769 }
770}
771
772static int test_op(struct event_format *event,
773 struct filter_arg *arg, struct record *record)
774{
775 switch (arg->op.type) {
776 case FILTER_OP_AND:
777 return test_filter(event, arg->op.left, record) &&
778 test_filter(event, arg->op.right, record);
779
780 case FILTER_OP_OR:
781 return test_filter(event, arg->op.left, record) ||
782 test_filter(event, arg->op.right, record);
783
784 case FILTER_OP_NOT:
785 return !test_filter(event, arg->op.right, record);
786
787 default:
788 /* ?? */
789 return 0;
790 }
791}
792
793static int test_filter(struct event_format *event,
794 struct filter_arg *arg, struct record *record)
795{
796 switch (arg->type) {
797 case FILTER_ARG_BOOLEAN:
798 /* easy case */
799 return arg->bool.value;
800
801 case FILTER_ARG_OP:
802 return test_op(event, arg, record);
803
804 case FILTER_ARG_NUM:
805 return test_num(event, arg, record);
806
807 case FILTER_ARG_STR:
808 return test_str(event, arg, record);
809
810 default:
811 /* ?? */
812 return 0;
813 }
814}
815
816/**
817 * pevent_filter_match - test if a record matches a filter
818 * @filter: filter struct with filter information
819 * @record: the record to test against the filter
820 *
821 * Returns:
822 * 1 - filter found for event and @record matches
823 * 0 - filter found for event and @record does not match
824 * -1 - no filter found for @record's event
825 * -2 - if no filters exist
826 */
827int pevent_filter_match(struct event_filter *filter,
828 struct record *record)
829{
830 struct pevent *pevent = filter->pevent;
831 struct filter_type *filter_type;
832 int event_id;
833
834 if (!filter->filters)
835 return FILTER_NONE;
836
837 event_id = pevent_data_type(pevent, record);
838
839 filter_type = find_filter_type(filter, event_id);
840
841 if (!filter_type)
842 return FILTER_NOEXIST;
843
844 return test_filter(filter_type->event, filter_type->filter, record) ?
845 FILTER_MATCH : FILTER_MISS;
846}
847
diff --git a/trace-cmd.c b/trace-cmd.c
index d866d8f..a50773e 100644
--- a/trace-cmd.c
+++ b/trace-cmd.c
@@ -1035,12 +1035,13 @@ void usage(char **argv)
1035 " Disables the tracer (may reset trace file)\n" 1035 " Disables the tracer (may reset trace file)\n"
1036 " Used in conjunction with start\n" 1036 " Used in conjunction with start\n"
1037 "\n" 1037 "\n"
1038 " %s report [-i file] [--cpu cpu] [-e][-f][-l][-P][-E]\n" 1038 " %s report [-i file] [--cpu cpu] [-e][-f][-l][-P][-E][-F filter]\n"
1039 " -i input file [default trace.dat]\n" 1039 " -i input file [default trace.dat]\n"
1040 " -e show file endianess\n" 1040 " -e show file endianess\n"
1041 " -f show function list\n" 1041 " -f show function list\n"
1042 " -P show printk list\n" 1042 " -P show printk list\n"
1043 " -E show event files stored\n" 1043 " -E show event files stored\n"
1044 " -F filter to filter output on\n"
1044 " -l show latency format (default with latency tracers)\n" 1045 " -l show latency format (default with latency tracers)\n"
1045 "\n" 1046 "\n"
1046 " %s split [options] -o file [start [end]]\n" 1047 " %s split [options] -o file [start [end]]\n"
diff --git a/trace-read.c b/trace-read.c
index 8768f11..c05fc5d 100644
--- a/trace-read.c
+++ b/trace-read.c
@@ -38,6 +38,14 @@
38 38
39#include "trace-local.h" 39#include "trace-local.h"
40 40
41static struct filter {
42 struct filter *next;
43 const char *filter;
44} *filter_strings;
45static struct filter **filter_next = &filter_strings;
46
47static struct event_filter *event_filters;
48
41static unsigned int page_size; 49static unsigned int page_size;
42static int input_fd; 50static int input_fd;
43const char *input_file = "trace.dat"; 51const char *input_file = "trace.dat";
@@ -189,12 +197,58 @@ static void test_save(struct record *record, int cpu)
189} 197}
190#endif 198#endif
191 199
200static void add_filter(const char *filter)
201{
202 struct filter *ftr;
203
204 ftr = malloc_or_die(sizeof(*ftr));
205 ftr->filter = filter;
206 ftr->next = NULL;
207
208 /* must maintain order of command line */
209 *filter_next = ftr;
210 filter_next = &ftr->next;
211}
212
213static void process_filters(struct tracecmd_input *handle)
214{
215 struct pevent *pevent;
216 struct filter *filter;
217 char *errstr;
218 int ret;
219
220 pevent = tracecmd_get_pevent(handle);
221 event_filters = pevent_filter_alloc(pevent);
222
223 while (filter_strings) {
224 filter = filter_strings;
225 filter_strings = filter->next;
226 ret = pevent_filter_add_filter_str(event_filters,
227 filter->filter,
228 &errstr);
229 if (ret < 0)
230 die("Error filtering: %s\n %s",
231 filter->filter, errstr);
232 free(errstr);
233 free(filter);
234 }
235}
236
237static int filter_record(struct tracecmd_input *handle,
238 struct record *record)
239{
240 return 0;
241}
242
192static void show_data(struct tracecmd_input *handle, 243static void show_data(struct tracecmd_input *handle,
193 struct record *record, int cpu) 244 struct record *record, int cpu)
194{ 245{
195 struct pevent *pevent; 246 struct pevent *pevent;
196 struct trace_seq s; 247 struct trace_seq s;
197 248
249 if (filter_record(handle, record))
250 return;
251
198 pevent = tracecmd_get_pevent(handle); 252 pevent = tracecmd_get_pevent(handle);
199 253
200 test_save(record, cpu); 254 test_save(record, cpu);
@@ -241,6 +295,8 @@ static void read_data_info(struct tracecmd_input *handle)
241 return; 295 return;
242 } 296 }
243 297
298 process_filters(handle);
299
244 do { 300 do {
245 next = -1; 301 next = -1;
246 ts = 0; 302 ts = 0;
@@ -251,7 +307,13 @@ static void read_data_info(struct tracecmd_input *handle)
251 record = tracecmd_read_next_data(handle, &cpu); 307 record = tracecmd_read_next_data(handle, &cpu);
252 308
253 if (record) { 309 if (record) {
254 show_data(handle, record, next); 310 ret = pevent_filter_match(event_filters, record);
311 switch (ret) {
312 case FILTER_NONE:
313 case FILTER_MATCH:
314 show_data(handle, record, next);
315 break;
316 }
255 free_record(record); 317 free_record(record);
256 } 318 }
257 } while (record); 319 } while (record);
@@ -296,7 +358,7 @@ void trace_report (int argc, char **argv)
296 {NULL, 0, NULL, 0} 358 {NULL, 0, NULL, 0}
297 }; 359 };
298 360
299 c = getopt_long (argc-1, argv+1, "+hi:fepPlE", 361 c = getopt_long (argc-1, argv+1, "+hi:fepPlEF:",
300 long_options, &option_index); 362 long_options, &option_index);
301 if (c == -1) 363 if (c == -1)
302 break; 364 break;
@@ -307,6 +369,9 @@ void trace_report (int argc, char **argv)
307 case 'i': 369 case 'i':
308 input_file = optarg; 370 input_file = optarg;
309 break; 371 break;
372 case 'F':
373 add_filter(optarg);
374 break;
310 case 'f': 375 case 'f':
311 show_funcs = 1; 376 show_funcs = 1;
312 break; 377 break;