9c312311 |
1 | /* This file is part of the Linux Trace Toolkit viewer |
0769c82f |
2 | * Copyright (C) 2003-2005 Michel Dagenais |
9c312311 |
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 Version 2 as |
6 | * published by the Free Software Foundation; |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program; if not, write to the Free Software |
15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
16 | * MA 02111-1307, USA. |
17 | */ |
18 | |
31452f49 |
19 | /* |
a4c292d4 |
20 | read_token |
48f6f3c2 |
21 | |
a4c292d4 |
22 | read_expression |
23 | ( read expr ) |
24 | simple expr [ op expr ] |
48f6f3c2 |
25 | |
a4c292d4 |
26 | read_simple_expression |
27 | read_field_path [ rel value ] |
48f6f3c2 |
28 | |
a4c292d4 |
29 | read_field_path |
30 | read_field_component [. field path] |
48f6f3c2 |
31 | |
a4c292d4 |
32 | read_field_component |
33 | name [ \[ value \] ] |
48f6f3c2 |
34 | |
a4c292d4 |
35 | data struct: |
36 | and/or(left/right) |
37 | not(child) |
38 | op(left/right) |
39 | path(component...) -> field |
150f0d33 |
40 | |
41 | consist in AND, OR and NOT nested expressions, forming a tree with |
42 | simple relations as leaves. The simple relations test is a field |
43 | in an event is equal, not equal, smaller, smaller or equal, larger, or |
44 | larger or equal to a specified value. |
31452f49 |
45 | */ |
46 | |
150f0d33 |
47 | /* |
48 | * YET TO BE ANSWERED |
49 | * - none yet |
50 | */ |
51 | |
52 | /* |
53 | * TODO |
54 | * - refine switch of expression in multiple uses functions |
55 | * - remove the idle expressions in the tree **** |
56 | * - add the current simple expression to the tree |
57 | */ |
58 | |
59 | #include <lttv/filter.h> |
60 | |
61 | /* |
1a7fa682 |
62 | GQuark |
63 | LTTV_FILTER_TRACE, |
64 | LTTV_FILTER_TRACESET, |
65 | LTTV_FILTER_TRACEFILE, |
66 | LTTV_FILTER_STATE, |
91ad3f0a |
67 | LTTV_FILTER_EVENT, |
68 | LTTV_FILTER_NAME, |
69 | LTTV_FILTER_CATEGORY, |
70 | LTTV_FILTER_TIME, |
71 | LTTV_FILTER_TSC, |
72 | LTTV_FILTER_PID, |
73 | LTTV_FILTER_PPID, |
74 | LTTV_FILTER_C_TIME, |
75 | LTTV_FILTER_I_TIME, |
76 | LTTV_FILTER_P_NAME, |
77 | LTTV_FILTER_EX_MODE, |
78 | LTTV_FILTER_EX_SUBMODE, |
79 | LTTV_FILTER_P_STATUS, |
80 | LTTV_FILTER_CPU; |
150f0d33 |
81 | */ |
0cdc2470 |
82 | |
2ea36caf |
83 | LttvSimpleExpression* |
0cdc2470 |
84 | lttv_simple_expression_new() { |
85 | |
86 | } |
f4e9dd16 |
87 | /** |
150f0d33 |
88 | * add a node to the current tree |
89 | * @param stack the tree stack |
90 | * @param subtree the subtree if available (pointer or NULL) |
91 | * @param op the logical operator that will form the node |
f4e9dd16 |
92 | */ |
0cdc2470 |
93 | void |
5b729fcf |
94 | lttv_filter_tree_add_node(GPtrArray* stack, LttvFilterTree* subtree, LttvLogicalOp op) { |
0cdc2470 |
95 | |
5b729fcf |
96 | LttvFilterTree* t1 = NULL; |
97 | LttvFilterTree* t2 = NULL; |
0cdc2470 |
98 | |
5b729fcf |
99 | t1 = (LttvFilterTree*)g_ptr_array_index(stack,stack->len-1); |
0cdc2470 |
100 | while(t1->right != LTTV_TREE_IDLE) t1 = t1->r_child.t; |
101 | t2 = lttv_filter_tree_new(); |
102 | t2->node = op; |
103 | if(subtree != NULL) { |
104 | t2->left = LTTV_TREE_NODE; |
105 | t2->l_child.t = subtree; |
106 | subtree = NULL; |
107 | t1->right = LTTV_TREE_NODE; |
108 | t1->r_child.t = t2; |
109 | } else { |
110 | // a_simple_expression->value = a_field_component->str; |
111 | // a_field_component = g_string_new(""); |
112 | t2->left = LTTV_TREE_LEAF; |
113 | // t2->l_child.leaf = a_simple_expression; |
114 | // a_simple_expression = g_new(lttv_simple_expression,1); |
115 | t1->right = LTTV_TREE_NODE; |
116 | t1->r_child.t = t2; |
117 | } |
118 | |
119 | } |
120 | |
0769c82f |
121 | /** |
122 | * Parse through filtering field hierarchy as specified |
123 | * by user. This function compares each value to |
124 | * predetermined quarks |
125 | * @param fp The field path list |
126 | * @return success/failure of operation |
127 | */ |
128 | gboolean |
47aa6e58 |
129 | parse_field_path(GPtrArray* fp, LttvSimpleExpression* se) { |
0769c82f |
130 | |
f4e9dd16 |
131 | GString* f = NULL; |
2b99ec10 |
132 | if(fp->len < 2) return FALSE; |
f4e9dd16 |
133 | g_assert(f=g_ptr_array_index(fp,0)); //list_first(fp)->data; |
47aa6e58 |
134 | |
135 | /* |
136 | * Parse through the specified |
137 | * hardcoded fields. |
138 | * |
139 | * Take note however that the |
140 | * 'event' subfields might change |
141 | * depending on values specified |
142 | * in core.xml file. Hence, if |
143 | * none of the subfields in the |
144 | * array match the hardcoded |
145 | * subfields, it will be considered |
146 | * as a dynamic field |
147 | */ |
148 | if(g_strcasecmp(f->str,"trace") ) { |
149 | /* |
150 | * Possible values: |
151 | * trace.name |
152 | */ |
153 | f=g_ptr_array_index(fp,1); |
154 | if(g_strcasecmp(f->str,"name")) {} |
155 | else return FALSE; |
156 | } else if(g_strcasecmp(f->str,"traceset") ) { |
157 | /* |
158 | * FIXME: not yet implemented ! |
159 | */ |
160 | } else if(g_strcasecmp(f->str,"tracefile") ) { |
161 | /* |
162 | * Possible values: |
163 | * tracefile.name |
164 | */ |
165 | f=g_ptr_array_index(fp,1); |
166 | if(g_strcasecmp(f->str,"name")) {} |
167 | else return FALSE; |
168 | } else if(g_strcasecmp(f->str,"state") ) { |
169 | /* |
170 | * Possible values: |
171 | * state.pid |
172 | * state.ppid |
173 | * state.creation_time |
174 | * state.insertion_time |
175 | * state.process_name |
176 | * state.execution_mode |
177 | * state.execution_submode |
178 | * state.process_status |
179 | * state.cpu |
180 | */ |
181 | f=g_ptr_array_index(fp,1); |
182 | if(g_strcasecmp(f->str,"pid") ) {} |
183 | else if(g_strcasecmp(f->str,"ppid") ) {} |
184 | else if(g_strcasecmp(f->str,"creation_time") ) {} |
185 | else if(g_strcasecmp(f->str,"insertion_time") ) {} |
186 | else if(g_strcasecmp(f->str,"process_name") ) {} |
187 | else if(g_strcasecmp(f->str,"execution_mode") ) {} |
188 | else if(g_strcasecmp(f->str,"execution_submode") ) {} |
189 | else if(g_strcasecmp(f->str,"process_status") ) {} |
190 | else if(g_strcasecmp(f->str,"cpu") ) {} |
191 | else return FALSE; |
192 | } else if(g_strcasecmp(f->str,"event") ) { |
2b99ec10 |
193 | f=g_ptr_array_index(fp,1); |
47aa6e58 |
194 | if(g_strcasecmp(f->str,"name") ) {} |
195 | else if(g_strcasecmp(f->str,"category") ) {} |
196 | else if(g_strcasecmp(f->str,"time") ) { |
2b99ec10 |
197 | // offset = &((LttEvent*)NULL)->event_time); |
198 | } |
47aa6e58 |
199 | else if(g_strcasecmp(f->str,"tsc") ) { |
2b99ec10 |
200 | // offset = &((LttEvent*)NULL)->event_cycle_count); |
201 | } |
202 | else { /* core.xml specified options */ |
203 | |
204 | } |
91ad3f0a |
205 | } else { |
206 | g_warning("Unrecognized field in filter string"); |
207 | return FALSE; |
0769c82f |
208 | } |
47aa6e58 |
209 | |
91ad3f0a |
210 | return TRUE; |
0769c82f |
211 | } |
212 | |
31452f49 |
213 | /** |
84a333d6 |
214 | * Add an filtering option to the current tree |
215 | * @param expression Current expression to parse |
216 | * @return success/failure of operation |
217 | */ |
218 | gboolean |
219 | parse_simple_expression(GString* expression) { |
220 | |
221 | unsigned i; |
222 | |
a4c292d4 |
223 | |
0769c82f |
224 | |
a4c292d4 |
225 | |
84a333d6 |
226 | } |
227 | |
150f0d33 |
228 | /** |
229 | * Applies the 'equal' operator to the |
47aa6e58 |
230 | * specified structure and value |
231 | * @param v1 left member of comparison |
232 | * @param v2 right member of comparison |
150f0d33 |
233 | * @return success/failure of operation |
234 | */ |
47aa6e58 |
235 | gboolean lttv_apply_op_eq_uint64(guint64 v1, guint64 v2) {} |
150f0d33 |
236 | |
5b729fcf |
237 | /** |
238 | * Applies the 'equal' operator to the |
47aa6e58 |
239 | * specified structure and value |
240 | * @param v1 left member of comparison |
241 | * @param v2 right member of comparison |
5b729fcf |
242 | * @return success/failure of operation |
243 | */ |
47aa6e58 |
244 | gboolean lttv_apply_op_eq_uint32(guint32 v1, guint32 v2) {} |
5b729fcf |
245 | |
246 | /** |
247 | * Applies the 'equal' operator to the |
47aa6e58 |
248 | * specified structure and value |
249 | * @param v1 left member of comparison |
250 | * @param v2 right member of comparison |
5b729fcf |
251 | * @return success/failure of operation |
252 | */ |
47aa6e58 |
253 | gboolean lttv_apply_op_eq_uint16(guint16 v1, guint16 v2) {} |
5b729fcf |
254 | |
255 | /** |
256 | * Applies the 'equal' operator to the |
47aa6e58 |
257 | * specified structure and value |
258 | * @param v1 left member of comparison |
259 | * @param v2 right member of comparison |
5b729fcf |
260 | * @return success/failure of operation |
261 | */ |
47aa6e58 |
262 | gboolean lttv_apply_op_eq_double(double v1, double v2) {} |
5b729fcf |
263 | |
264 | /** |
265 | * Applies the 'equal' operator to the |
47aa6e58 |
266 | * specified structure and value |
267 | * @param v1 left member of comparison |
268 | * @param v2 right member of comparison |
5b729fcf |
269 | * @return success/failure of operation |
270 | */ |
47aa6e58 |
271 | gboolean lttv_apply_op_eq_string(char* v1, char* v2) {} |
150f0d33 |
272 | |
273 | /** |
274 | * Applies the 'not equal' operator to the |
47aa6e58 |
275 | * specified structure and value |
276 | * @param v1 left member of comparison |
277 | * @param v2 right member of comparison |
150f0d33 |
278 | * @return success/failure of operation |
279 | */ |
47aa6e58 |
280 | gboolean lttv_apply_op_ne_uint64(guint64 v1, guint64 v2) {} |
150f0d33 |
281 | |
5b729fcf |
282 | /** |
283 | * Applies the 'not equal' operator to the |
47aa6e58 |
284 | * specified structure and value |
285 | * @param v1 left member of comparison |
286 | * @param v2 right member of comparison |
5b729fcf |
287 | * @return success/failure of operation |
288 | */ |
47aa6e58 |
289 | gboolean lttv_apply_op_ne_uint32(guint32 v1, guint32 v2) {} |
5b729fcf |
290 | |
291 | /** |
292 | * Applies the 'not equal' operator to the |
47aa6e58 |
293 | * specified structure and value |
294 | * @param v1 left member of comparison |
295 | * @param v2 right member of comparison |
5b729fcf |
296 | * @return success/failure of operation |
297 | */ |
47aa6e58 |
298 | gboolean lttv_apply_op_ne_uint16(guint16 v1, guint16 v2) {} |
5b729fcf |
299 | |
300 | /** |
301 | * Applies the 'not equal' operator to the |
47aa6e58 |
302 | * specified structure and value |
303 | * @param v1 left member of comparison |
304 | * @param v2 right member of comparison |
5b729fcf |
305 | * @return success/failure of operation |
306 | */ |
47aa6e58 |
307 | gboolean lttv_apply_op_ne_double(double v1, double v2) {} |
5b729fcf |
308 | |
309 | /** |
310 | * Applies the 'not equal' operator to the |
47aa6e58 |
311 | * specified structure and value |
312 | * @param v1 left member of comparison |
313 | * @param v2 right member of comparison |
5b729fcf |
314 | * @return success/failure of operation |
315 | */ |
47aa6e58 |
316 | gboolean lttv_apply_op_ne_string(char* v1, char* v2) {} |
150f0d33 |
317 | |
318 | /** |
319 | * Applies the 'lower than' operator to the |
47aa6e58 |
320 | * specified structure and value |
321 | * @param v1 left member of comparison |
322 | * @param v2 right member of comparison |
150f0d33 |
323 | * @return success/failure of operation |
324 | */ |
47aa6e58 |
325 | gboolean lttv_apply_op_lt_uint64(guint64 v1, guint64 v2) {} |
150f0d33 |
326 | |
5b729fcf |
327 | /** |
328 | * Applies the 'lower than' operator to the |
47aa6e58 |
329 | * specified structure and value |
330 | * @param v1 left member of comparison |
331 | * @param v2 right member of comparison |
5b729fcf |
332 | * @return success/failure of operation |
333 | */ |
47aa6e58 |
334 | gboolean lttv_apply_op_lt_uint32(guint32 v1, guint32 v2) {} |
5b729fcf |
335 | |
336 | /** |
337 | * Applies the 'lower than' operator to the |
47aa6e58 |
338 | * specified structure and value |
339 | * @param v1 left member of comparison |
340 | * @param v2 right member of comparison |
5b729fcf |
341 | * @return success/failure of operation |
342 | */ |
47aa6e58 |
343 | gboolean lttv_apply_op_lt_uint16(guint16 v1, guint16 v2) {} |
5b729fcf |
344 | |
345 | /** |
346 | * Applies the 'lower than' operator to the |
47aa6e58 |
347 | * specified structure and value |
348 | * @param v1 left member of comparison |
349 | * @param v2 right member of comparison |
5b729fcf |
350 | * @return success/failure of operation |
351 | */ |
47aa6e58 |
352 | gboolean lttv_apply_op_lt_double(double v1, double v2) {} |
5b729fcf |
353 | |
354 | /** |
355 | * Applies the 'lower than' operator to the |
47aa6e58 |
356 | * specified structure and value |
357 | * @param v1 left member of comparison |
358 | * @param v2 right member of comparison |
5b729fcf |
359 | * @return success/failure of operation |
360 | */ |
47aa6e58 |
361 | gboolean lttv_apply_op_le_uint64(guint64 v1, guint64 v2) {} |
150f0d33 |
362 | |
363 | /** |
364 | * Applies the 'lower or equal' operator to the |
47aa6e58 |
365 | * specified structure and value |
366 | * @param v1 left member of comparison |
367 | * @param v2 right member of comparison |
150f0d33 |
368 | * @return success/failure of operation |
369 | */ |
47aa6e58 |
370 | gboolean lttv_apply_op_le_uint32(guint32 v1, guint32 v2) {} |
150f0d33 |
371 | |
5b729fcf |
372 | /** |
373 | * Applies the 'lower or equal' operator to the |
47aa6e58 |
374 | * specified structure and value |
375 | * @param v1 left member of comparison |
376 | * @param v2 right member of comparison |
5b729fcf |
377 | * @return success/failure of operation |
378 | */ |
47aa6e58 |
379 | gboolean lttv_apply_op_le_uint16(guint16 v1, guint16 v2) {} |
5b729fcf |
380 | |
381 | /** |
382 | * Applies the 'lower or equal' operator to the |
47aa6e58 |
383 | * specified structure and value |
384 | * @param v1 left member of comparison |
385 | * @param v2 right member of comparison |
5b729fcf |
386 | * @return success/failure of operation |
387 | */ |
47aa6e58 |
388 | gboolean lttv_apply_op_le_double(double v1, double v2) {} |
5b729fcf |
389 | |
390 | /** |
391 | * Applies the 'lower or equal' operator to the |
47aa6e58 |
392 | * specified structure and value |
393 | * @param v1 left member of comparison |
394 | * @param v2 right member of comparison |
5b729fcf |
395 | * @return success/failure of operation |
396 | */ |
47aa6e58 |
397 | gboolean lttv_apply_op_gt_uint64(guint64 v1, guint64 v2) {} |
150f0d33 |
398 | |
399 | /** |
400 | * Applies the 'greater than' operator to the |
47aa6e58 |
401 | * specified structure and value |
402 | * @param v1 left member of comparison |
403 | * @param v2 right member of comparison |
150f0d33 |
404 | * @return success/failure of operation |
405 | */ |
47aa6e58 |
406 | gboolean lttv_apply_op_gt_uint32(guint32 v1, guint32 v2) {} |
150f0d33 |
407 | |
5b729fcf |
408 | /** |
409 | * Applies the 'greater than' operator to the |
47aa6e58 |
410 | * specified structure and value |
411 | * @param v1 left member of comparison |
412 | * @param v2 right member of comparison |
5b729fcf |
413 | * @return success/failure of operation |
414 | */ |
47aa6e58 |
415 | gboolean lttv_apply_op_gt_uint16(guint16 v1, guint16 v2) {} |
5b729fcf |
416 | |
417 | /** |
418 | * Applies the 'greater than' operator to the |
47aa6e58 |
419 | * specified structure and value |
420 | * @param v1 left member of comparison |
421 | * @param v2 right member of comparison |
5b729fcf |
422 | * @return success/failure of operation |
423 | */ |
47aa6e58 |
424 | gboolean lttv_apply_op_gt_double(double v1, double v2) {} |
5b729fcf |
425 | |
426 | /** |
427 | * Applies the 'greater than' operator to the |
47aa6e58 |
428 | * specified structure and value |
429 | * @param v1 left member of comparison |
430 | * @param v2 right member of comparison |
5b729fcf |
431 | * @return success/failure of operation |
432 | */ |
47aa6e58 |
433 | gboolean lttv_apply_op_ge_uint64(guint64 v1, guint64 v2) {} |
150f0d33 |
434 | |
435 | /** |
436 | * Applies the 'greater or equal' operator to the |
47aa6e58 |
437 | * specified structure and value |
438 | * @param v1 left member of comparison |
439 | * @param v2 right member of comparison |
150f0d33 |
440 | * @return success/failure of operation |
441 | */ |
47aa6e58 |
442 | gboolean lttv_apply_op_ge_uint32(guint32 v1, guint32 v2) {} |
150f0d33 |
443 | |
5b729fcf |
444 | /** |
445 | * Applies the 'greater or equal' operator to the |
47aa6e58 |
446 | * specified structure and value |
447 | * @param v1 left member of comparison |
448 | * @param v2 right member of comparison |
5b729fcf |
449 | * @return success/failure of operation |
450 | */ |
47aa6e58 |
451 | gboolean lttv_apply_op_ge_uint16(guint16 v1, guint16 v2) {} |
150f0d33 |
452 | |
5b729fcf |
453 | /** |
454 | * Applies the 'greater or equal' operator to the |
47aa6e58 |
455 | * specified structure and value |
456 | * @param v1 left member of comparison |
457 | * @param v2 right member of comparison |
5b729fcf |
458 | * @return success/failure of operation |
459 | */ |
47aa6e58 |
460 | gboolean lttv_apply_op_ge_double(double v1, double v2) {} |
150f0d33 |
461 | |
462 | |
463 | /** |
464 | * Makes a copy of the current filter tree |
465 | * @param tree pointer to the current tree |
466 | * @return new copy of the filter tree |
467 | */ |
468 | LttvFilterTree* |
469 | lttv_filter_tree_clone(LttvFilterTree* tree) { |
470 | |
471 | |
472 | |
473 | } |
474 | |
475 | /** |
476 | * Makes a copy of the current filter |
477 | * @param filter pointer to the current filter |
478 | * @return new copy of the filter |
479 | */ |
480 | LttvFilter* |
481 | lttv_filter_clone(LttvFilter* filter) { |
482 | |
483 | |
484 | LttvFilter* newfilter = g_new(LttvFilter,1); |
485 | |
486 | // newfilter->expression = g_new(char,1) |
487 | strcpy(newfilter->expression,filter->expression); |
488 | |
489 | newfilter->head = lttv_filter_tree_clone(filter->head); |
490 | |
491 | return newfilter; |
492 | |
493 | } |
494 | |
495 | |
84a333d6 |
496 | /** |
497 | * Creates a new lttv_filter |
31452f49 |
498 | * @param expression filtering options string |
499 | * @param t pointer to the current LttvTrace |
84a333d6 |
500 | * @return the current lttv_filter or NULL if error |
31452f49 |
501 | */ |
2ea36caf |
502 | LttvFilter* |
0769c82f |
503 | lttv_filter_new(char *expression, LttvTraceState *tcs) { |
a4c292d4 |
504 | |
0769c82f |
505 | g_print("filter::lttv_filter_new()\n"); /* debug */ |
a4c292d4 |
506 | |
a4c292d4 |
507 | unsigned |
508 | i, |
91ad3f0a |
509 | p_nesting=0, /* parenthesis nesting value */ |
a4c292d4 |
510 | b=0; /* current breakpoint in expression string */ |
1601b365 |
511 | |
512 | /* trees */ |
5b729fcf |
513 | LttvFilterTree |
1601b365 |
514 | *tree = lttv_filter_tree_new(), /* main tree */ |
515 | *subtree = NULL, /* buffer for subtrees */ |
516 | *t1, /* buffer #1 */ |
517 | *t2; /* buffer #2 */ |
518 | |
519 | /* |
520 | * Tree Stack |
f4e9dd16 |
521 | * each element of the list |
522 | * is a sub tree created |
523 | * by the use of parenthesis in the |
524 | * global expression. The final tree |
1601b365 |
525 | * will be the one left at the root of |
f4e9dd16 |
526 | * the list |
527 | */ |
18d1226f |
528 | GPtrArray *tree_stack = g_ptr_array_new(); |
529 | g_ptr_array_add( tree_stack,(gpointer) tree ); |
f4e9dd16 |
530 | |
a4c292d4 |
531 | /* temporary values */ |
0769c82f |
532 | GString *a_field_component = g_string_new(""); |
f4e9dd16 |
533 | GPtrArray *a_field_path = NULL; |
534 | |
2ea36caf |
535 | LttvSimpleExpression* a_simple_expression = g_new(LttvSimpleExpression,1); |
0769c82f |
536 | |
a4c292d4 |
537 | /* |
538 | * Parse entire expression and construct |
539 | * the binary tree. There are two steps |
540 | * in browsing that string |
f4e9dd16 |
541 | * 1. finding boolean ops " &,|,^,! " and parenthesis " {,(,[,],),} " |
a4c292d4 |
542 | * 2. finding simple expressions |
0769c82f |
543 | * - field path ( separated by dots ) |
a4c292d4 |
544 | * - op ( >, <, =, >=, <=, !=) |
0769c82f |
545 | * - value ( integer, string ... ) |
546 | * To spare computing time, the whole |
547 | * string is parsed in this loop for a |
548 | * O(n) complexity order. |
1601b365 |
549 | * |
18d1226f |
550 | * When encountering logical op &,|,^ |
551 | * 1. parse the last value if any |
552 | * 2. create a new tree |
553 | * 3. add the expression (simple exp, or exp (subtree)) to the tree |
554 | * 4. concatenate this tree with the current tree on top of the stack |
555 | * When encountering math ops >,>=,<,<=,=,!= |
556 | * 1. add to op to the simple expression |
557 | * 2. concatenate last field component to field path |
558 | * When encountering concatening ops . |
559 | * 1. concatenate last field component to field path |
560 | * When encountering opening parenthesis (,{,[ |
561 | * 1. create a new subtree on top of tree stack |
562 | * When encountering closing parenthesis ),},] |
563 | * 1. add the expression on right child of the current tree |
564 | * 2. the subtree is completed, allocate a new subtree |
565 | * 3. pop the tree value from the tree stack |
566 | */ |
567 | |
f4e9dd16 |
568 | a_field_path = g_ptr_array_new(); |
569 | g_ptr_array_set_size(a_field_path,2); /* by default, recording 2 field expressions */ |
570 | |
18d1226f |
571 | |
a4c292d4 |
572 | for(i=0;i<strlen(expression);i++) { |
18d1226f |
573 | // g_print("%s\n",a_field_component->str); |
410c83da |
574 | g_print("%c ",expression[i]); |
1601b365 |
575 | // g_print("switch:%c -->subtree:%p\n",expression[i],subtree); |
a4c292d4 |
576 | switch(expression[i]) { |
577 | /* |
578 | * logical operators |
579 | */ |
580 | case '&': /* and */ |
5b729fcf |
581 | t1 = (LttvFilterTree*)g_ptr_array_index(tree_stack,tree_stack->len-1); |
2a734d8e |
582 | while(t1->right != LTTV_TREE_IDLE) t1 = t1->r_child.t; |
18d1226f |
583 | t2 = lttv_filter_tree_new(); |
0cdc2470 |
584 | t2->node = LTTV_LOGICAL_AND; |
1601b365 |
585 | if(subtree != NULL) { |
18d1226f |
586 | t2->left = LTTV_TREE_NODE; |
587 | t2->l_child.t = subtree; |
f4e9dd16 |
588 | subtree = NULL; |
18d1226f |
589 | t1->right = LTTV_TREE_NODE; |
410c83da |
590 | t1->r_child.t = t2; |
f4e9dd16 |
591 | } else { |
0cdc2470 |
592 | a_simple_expression->value = a_field_component->str; |
18d1226f |
593 | a_field_component = g_string_new(""); |
594 | t2->left = LTTV_TREE_LEAF; |
0cdc2470 |
595 | t2->l_child.leaf = a_simple_expression; |
2ea36caf |
596 | a_simple_expression = g_new(LttvSimpleExpression,1); |
18d1226f |
597 | t1->right = LTTV_TREE_NODE; |
410c83da |
598 | t1->r_child.t = t2; |
f4e9dd16 |
599 | } |
600 | |
601 | break; |
a4c292d4 |
602 | case '|': /* or */ |
2ea36caf |
603 | t1 = (LttvFilter*)g_ptr_array_index(tree_stack,tree_stack->len-1); |
2a734d8e |
604 | while(t1->right != LTTV_TREE_IDLE) t1 = t1->r_child.t; |
1601b365 |
605 | t2 = lttv_filter_tree_new(); |
0cdc2470 |
606 | t2->node = LTTV_LOGICAL_OR; |
1601b365 |
607 | if(subtree != NULL) { |
608 | t2->left = LTTV_TREE_NODE; |
609 | t2->l_child.t = subtree; |
610 | subtree = NULL; |
611 | t1->right = LTTV_TREE_NODE; |
612 | t1->r_child.t = t2; |
613 | } else { |
0cdc2470 |
614 | a_simple_expression->value = a_field_component->str; |
1601b365 |
615 | a_field_component = g_string_new(""); |
616 | t2->left = LTTV_TREE_LEAF; |
0cdc2470 |
617 | t2->l_child.leaf = a_simple_expression; |
2ea36caf |
618 | a_simple_expression = g_new(LttvSimpleExpression,1); |
1601b365 |
619 | t1->right = LTTV_TREE_NODE; |
620 | t1->r_child.t = t2; |
621 | } |
f4e9dd16 |
622 | break; |
a4c292d4 |
623 | case '^': /* xor */ |
2ea36caf |
624 | t1 = (LttvFilter*)g_ptr_array_index(tree_stack,tree_stack->len-1); |
2a734d8e |
625 | while(t1->right != LTTV_TREE_IDLE) t1 = t1->r_child.t; |
1601b365 |
626 | t2 = lttv_filter_tree_new(); |
0cdc2470 |
627 | t2->node = LTTV_LOGICAL_XOR; |
1601b365 |
628 | if(subtree != NULL) { |
629 | t2->left = LTTV_TREE_NODE; |
630 | t2->l_child.t = subtree; |
631 | subtree = NULL; |
632 | t1->right = LTTV_TREE_NODE; |
633 | t1->r_child.t = t2; |
634 | } else { |
0cdc2470 |
635 | a_simple_expression->value = a_field_component->str; |
1601b365 |
636 | a_field_component = g_string_new(""); |
637 | t2->left = LTTV_TREE_LEAF; |
0cdc2470 |
638 | t2->l_child.leaf = a_simple_expression; |
2ea36caf |
639 | a_simple_expression = g_new(LttvSimpleExpression,1); |
1601b365 |
640 | t1->right = LTTV_TREE_NODE; |
641 | t1->r_child.t = t2; |
642 | } |
a4c292d4 |
643 | break; |
644 | case '!': /* not, or not equal (math op) */ |
645 | if(expression[i+1] == '=') { /* != */ |
0cdc2470 |
646 | a_simple_expression->op = LTTV_FIELD_NE; |
a4c292d4 |
647 | i++; |
0cdc2470 |
648 | g_ptr_array_add( a_field_path,(gpointer) a_field_component ); |
649 | a_field_component = g_string_new(""); |
a4c292d4 |
650 | } else { /* ! */ |
1601b365 |
651 | // g_print("%s\n",a_field_component); |
652 | // a_field_component = g_string_new(""); |
2ea36caf |
653 | t1 = (LttvFilter*)g_ptr_array_index(tree_stack,tree_stack->len-1); |
2a734d8e |
654 | while(t1->right != LTTV_TREE_IDLE) t1 = t1->r_child.t; |
1601b365 |
655 | t2 = lttv_filter_tree_new(); |
0cdc2470 |
656 | t2->node = LTTV_LOGICAL_NOT; |
1601b365 |
657 | t1->right = LTTV_TREE_NODE; |
658 | t1->r_child.t = t2; |
a4c292d4 |
659 | } |
660 | break; |
661 | case '(': /* start of parenthesis */ |
91ad3f0a |
662 | case '[': |
663 | case '{': |
664 | p_nesting++; /* incrementing parenthesis nesting value */ |
1601b365 |
665 | t1 = lttv_filter_tree_new(); |
666 | g_ptr_array_add( tree_stack,(gpointer) t1 ); |
a4c292d4 |
667 | break; |
668 | case ')': /* end of parenthesis */ |
91ad3f0a |
669 | case ']': |
670 | case '}': |
671 | p_nesting--; /* decrementing parenthesis nesting value */ |
18d1226f |
672 | if(p_nesting<0 || tree_stack->len<2) { |
f4e9dd16 |
673 | g_warning("Wrong filtering options, the string\n\"%s\"\n\ |
674 | is not valid due to parenthesis incorrect use",expression); |
675 | return NULL; |
676 | } |
18d1226f |
677 | |
678 | g_assert(tree_stack->len>0); |
679 | if(subtree != NULL) { |
680 | t1 = g_ptr_array_index(tree_stack,tree_stack->len-1); |
2a734d8e |
681 | while(t1->right != LTTV_TREE_IDLE && t1->right != LTTV_TREE_LEAF) { |
18d1226f |
682 | g_assert(t1!=NULL && t1->r_child.t != NULL); |
683 | t1 = t1->r_child.t; |
684 | } |
685 | t1->right = LTTV_TREE_NODE; |
686 | t1->r_child.t = subtree; |
687 | subtree = g_ptr_array_index(tree_stack,tree_stack->len-1); |
688 | g_ptr_array_remove_index(tree_stack,tree_stack->len-1); |
689 | } else { |
0cdc2470 |
690 | a_simple_expression->value = a_field_component->str; |
18d1226f |
691 | a_field_component = g_string_new(""); |
692 | t1 = g_ptr_array_index(tree_stack,tree_stack->len-1); |
2a734d8e |
693 | while(t1->right != LTTV_TREE_IDLE) t1 = t1->r_child.t; |
18d1226f |
694 | t1->right = LTTV_TREE_LEAF; |
0cdc2470 |
695 | t1->r_child.leaf = a_simple_expression; |
2ea36caf |
696 | a_simple_expression = g_new(LttvSimpleExpression,1); |
18d1226f |
697 | subtree = g_ptr_array_index(tree_stack,tree_stack->len-1); |
1601b365 |
698 | g_assert(subtree != NULL); |
18d1226f |
699 | g_ptr_array_remove_index(tree_stack,tree_stack->len-1); |
700 | } |
a4c292d4 |
701 | break; |
702 | |
703 | /* |
704 | * mathematic operators |
705 | */ |
706 | case '<': /* lower, lower or equal */ |
707 | if(expression[i+1] == '=') { /* <= */ |
708 | i++; |
0cdc2470 |
709 | a_simple_expression->op = LTTV_FIELD_LE; |
710 | } else a_simple_expression->op = LTTV_FIELD_LT; |
f4e9dd16 |
711 | g_ptr_array_add( a_field_path,(gpointer) a_field_component ); |
712 | a_field_component = g_string_new(""); |
a4c292d4 |
713 | break; |
714 | case '>': /* higher, higher or equal */ |
715 | if(expression[i+1] == '=') { /* >= */ |
716 | i++; |
0cdc2470 |
717 | a_simple_expression->op = LTTV_FIELD_GE; |
718 | } else a_simple_expression->op = LTTV_FIELD_GT; |
f4e9dd16 |
719 | g_ptr_array_add( a_field_path,(gpointer) a_field_component ); |
720 | a_field_component = g_string_new(""); |
a4c292d4 |
721 | break; |
722 | case '=': /* equal */ |
0cdc2470 |
723 | a_simple_expression->op = LTTV_FIELD_EQ; |
f4e9dd16 |
724 | g_ptr_array_add( a_field_path,(gpointer) a_field_component ); |
725 | a_field_component = g_string_new(""); |
a4c292d4 |
726 | break; |
0769c82f |
727 | /* |
728 | * Field concatening caracter |
729 | */ |
730 | case '.': /* dot */ |
f4e9dd16 |
731 | g_ptr_array_add( a_field_path,(gpointer) a_field_component ); |
0769c82f |
732 | a_field_component = g_string_new(""); |
733 | break; |
a4c292d4 |
734 | default: /* concatening current string */ |
1a7fa682 |
735 | g_string_append_c(a_field_component,expression[i]); |
a4c292d4 |
736 | } |
737 | } |
1601b365 |
738 | |
739 | g_print("subtree:%p, tree:%p, t1:%p, t2:%p\n",subtree,tree,t1,t2); |
0cdc2470 |
740 | g_print("stack size: %i\n",tree_stack->len); |
741 | |
742 | /* |
743 | * Preliminary check to see |
744 | * if tree was constructed correctly |
745 | */ |
746 | if( p_nesting>0 ) { |
747 | g_warning("Wrong filtering options, the string\n\"%s\"\n\ |
748 | is not valid due to parenthesis incorrect use",expression); |
749 | return NULL; |
750 | } |
751 | |
752 | if(tree_stack->len != 1) /* only root tree should remain */ |
753 | return NULL; |
1601b365 |
754 | |
410c83da |
755 | /* processing last element of expression */ |
410c83da |
756 | t1 = g_ptr_array_index(tree_stack,tree_stack->len-1); |
2a734d8e |
757 | while(t1->right != LTTV_TREE_IDLE) t1 = t1->r_child.t; |
410c83da |
758 | if(subtree != NULL) { /* add the subtree */ |
759 | t1->right = LTTV_TREE_NODE; |
0cdc2470 |
760 | t1->r_child.t = subtree; |
410c83da |
761 | subtree = NULL; |
762 | } else { /* add a leaf */ |
0cdc2470 |
763 | a_simple_expression->value = a_field_component->str; |
410c83da |
764 | a_field_component = g_string_new(""); |
765 | t1->right = LTTV_TREE_LEAF; |
0cdc2470 |
766 | t1->r_child.leaf = a_simple_expression; |
2ea36caf |
767 | /* |
768 | * FIXME: is it really necessary to reallocate |
769 | * LttvSimpleExpression at this point ?? |
770 | */ |
771 | a_simple_expression = g_new(LttvSimpleExpression,1); |
410c83da |
772 | } |
773 | |
774 | g_assert(tree != NULL); |
775 | g_assert(subtree == NULL); |
a4c292d4 |
776 | |
1601b365 |
777 | lttv_filter_tracefile(tree,NULL); |
778 | |
410c83da |
779 | return tree; |
780 | |
31452f49 |
781 | } |
782 | |
1da1525d |
783 | void |
2ea36caf |
784 | lttv_filter_destroy(LttvFilter* filter) { |
1da1525d |
785 | |
786 | } |
787 | |
150f0d33 |
788 | /** |
789 | * Assign a new tree for the current expression |
790 | * or sub expression |
791 | * @return pointer of LttvFilterTree |
792 | */ |
793 | LttvFilterTree* lttv_filter_tree_new() { |
794 | LttvFilterTree* tree; |
795 | |
796 | tree = g_new(LttvFilter,1); |
797 | tree->node = 0; //g_new(lttv_expression,1); |
798 | // tree->node->type = LTTV_UNDEFINED_EXPRESSION; |
799 | tree->left = LTTV_TREE_IDLE; |
800 | tree->right = LTTV_TREE_IDLE; |
801 | |
802 | return tree; |
803 | } |
804 | |
805 | /** |
806 | * Destroys the tree and his sub-trees |
807 | * @param tree Tree which must be destroyed |
808 | */ |
809 | void lttv_filter_tree_destroy(LttvFilterTree* tree) { |
810 | |
811 | if(tree == NULL) return; |
812 | |
813 | if(tree->left == LTTV_TREE_LEAF) g_free(tree->l_child.leaf); |
814 | else if(tree->left == LTTV_TREE_NODE) lttv_filter_tree_destroy(tree->l_child.t); |
815 | |
816 | if(tree->right == LTTV_TREE_LEAF) g_free(tree->r_child.leaf); |
817 | else if(tree->right == LTTV_TREE_NODE) lttv_filter_tree_destroy(tree->r_child.t); |
818 | |
819 | g_free(tree->node); |
820 | g_free(tree); |
821 | } |
822 | |
823 | |
84a333d6 |
824 | /** |
825 | * Apply the filter to a specific trace |
826 | * @param filter the current filter applied |
827 | * @param tracefile the trace to apply the filter to |
828 | * @return success/failure of operation |
829 | */ |
31452f49 |
830 | gboolean |
2ea36caf |
831 | lttv_filter_tracefile(LttvFilter *filter, LttTracefile *tracefile) { |
0769c82f |
832 | |
5b729fcf |
833 | LttvFilterTree* t = filter->head; |
834 | |
1601b365 |
835 | /* |
836 | * Each tree is parsed in inorder. |
837 | * This way, it's possible to apply the left filter of the |
838 | * tree, then decide whether or not the right branch should |
839 | * be parsed depending on the linking logical operator |
840 | * |
841 | * As for the filtering structure, since we are trying |
842 | * to remove elements from the trace, it might be better |
843 | * managing an array of all items to be removed .. |
844 | */ |
0769c82f |
845 | |
5b729fcf |
846 | g_print("node:%p lchild:%p rchild:%p\n",t,t->l_child.t,t->r_child.t); |
847 | g_print("node type%i\n",t->node); |
848 | if(t->left == LTTV_TREE_NODE) lttv_filter_tracefile(t->l_child.t,NULL); |
849 | else if(t->left == LTTV_TREE_LEAF) { |
850 | g_assert(t->l_child.leaf->value != NULL); |
851 | g_print("%p: left is qqch %i %s\n",t,t->l_child.leaf->op,t->l_child.leaf->value); |
0cdc2470 |
852 | } |
5b729fcf |
853 | if(t->right == LTTV_TREE_NODE) lttv_filter_tracefile(t->r_child.t,NULL); |
854 | else if(t->right == LTTV_TREE_LEAF) { |
855 | g_assert(t->r_child.leaf->value != NULL); |
856 | g_print("%p: right is qqch %i %s\n",t,t->r_child.leaf->op,t->r_child.leaf->value); |
0cdc2470 |
857 | } |
0769c82f |
858 | |
859 | /* test */ |
860 | /* int i, nb; |
861 | char *f_name, *e_name; |
31452f49 |
862 | |
0769c82f |
863 | char* field = "cpu"; |
864 | |
865 | LttvTraceHook h; |
866 | |
867 | LttEventType *et; |
868 | |
869 | LttType *t; |
870 | |
871 | GString *fe_name = g_string_new(""); |
872 | |
873 | nb = ltt_trace_eventtype_number(tcs->parent.t); |
874 | g_print("NB:%i\n",nb); |
875 | for(i = 0 ; i < nb ; i++) { |
876 | et = ltt_trace_eventtype_get(tcs->parent.t, i); |
877 | e_name = ltt_eventtype_name(et); |
878 | f_name = ltt_facility_name(ltt_eventtype_facility(et)); |
879 | g_string_printf(fe_name, "%s.%s", f_name, e_name); |
880 | g_print("facility:%s and event:%s\n",f_name,e_name); |
881 | } |
882 | */ |
31452f49 |
883 | } |
884 | |
1a7fa682 |
885 | gboolean |
2ea36caf |
886 | lttv_filter_tracestate(LttvFilter *filter, LttvTraceState *tracestate) { |
341aa948 |
887 | |
888 | } |
1a7fa682 |
889 | |
84a333d6 |
890 | /** |
891 | * Apply the filter to a specific event |
892 | * @param filter the current filter applied |
893 | * @param event the event to apply the filter to |
894 | * @return success/failure of operation |
895 | */ |
31452f49 |
896 | gboolean |
2ea36caf |
897 | lttv_filter_event(LttvFilter *filter, LttEvent *event) { |
31452f49 |
898 | |
899 | } |
1a7fa682 |
900 | |
91ad3f0a |
901 | /** |
902 | * Initializes the filter module and specific values |
903 | */ |
1a7fa682 |
904 | static void module_init() |
905 | { |
91ad3f0a |
906 | |
907 | /* |
908 | * Quarks initialization |
909 | * for hardcoded filtering options |
910 | * |
911 | * TODO: traceset has no yet been defined |
912 | */ |
913 | |
914 | /* top fields */ |
5b729fcf |
915 | // LTTV_FILTER_EVENT = g_quark_from_string("event"); |
916 | // LTTV_FILTER_TRACE = g_quark_from_string("trace"); |
917 | // LTTV_FILTER_TRACESET = g_quark_from_string("traceset"); |
918 | // LTTV_FILTER_STATE = g_quark_from_string("state"); |
919 | // LTTV_FILTER_TRACEFILE = g_quark_from_string("tracefile"); |
1a7fa682 |
920 | |
91ad3f0a |
921 | /* event.name, tracefile.name, trace.name */ |
5b729fcf |
922 | // LTTV_FILTER_NAME = g_quark_from_string("name"); |
91ad3f0a |
923 | |
924 | /* event sub fields */ |
5b729fcf |
925 | // LTTV_FILTER_CATEGORY = g_quark_from_string("category"); |
926 | // LTTV_FILTER_TIME = g_quark_from_string("time"); |
927 | // LTTV_FILTER_TSC = g_quark_from_string("tsc"); |
91ad3f0a |
928 | |
929 | /* state sub fields */ |
5b729fcf |
930 | // LTTV_FILTER_PID = g_quark_from_string("pid"); |
931 | // LTTV_FILTER_PPID = g_quark_from_string("ppid"); |
932 | // LTTV_FILTER_C_TIME = g_quark_from_string("creation_time"); |
933 | // LTTV_FILTER_I_TIME = g_quark_from_string("insertion_time"); |
934 | // LTTV_FILTER_P_NAME = g_quark_from_string("process_name"); |
935 | // LTTV_FILTER_EX_MODE = g_quark_from_string("execution_mode"); |
936 | // LTTV_FILTER_EX_SUBMODE = g_quark_from_string("execution_submode"); |
937 | // LTTV_FILTER_P_STATUS = g_quark_from_string("process_status"); |
938 | // LTTV_FILTER_CPU = g_quark_from_string("cpu"); |
91ad3f0a |
939 | |
1a7fa682 |
940 | } |
941 | |
91ad3f0a |
942 | /** |
943 | * Destroys the filter module and specific values |
944 | */ |
1a7fa682 |
945 | static void module_destroy() |
946 | { |
947 | } |
948 | |
949 | |
91ad3f0a |
950 | LTTV_MODULE("filter", "Filters traceset and events", \ |
951 | "Filters traceset and events specifically to user input", \ |
1a7fa682 |
952 | module_init, module_destroy) |
953 | |
954 | |
955 | |