2 * Wireshark - Network traffic analyzer
3 * By Gerald Combs <gerald@wireshark.org>
4 * Copyright 2001 Gerald Combs
6 * SPDX-License-Identifier: GPL-2.0-or-later
11 #define WS_LOG_DOMAIN LOG_DOMAIN_DFILTER
13 #include "syntax-tree.h"
14 #include <wsutil/wmem/wmem.h>
15 #include <wsutil/str_util.h>
16 #include <wsutil/glib-compat.h>
17 #include "sttype-op.h"
18 #include "sttype-function.h"
19 #include "dfilter-int.h"
21 /* Keep track of sttype_t's via their sttype_id_t number */
22 static sttype_t
* type_list
[STTYPE_NUM_TYPES
];
28 sttype_register_field();
29 sttype_register_function();
30 sttype_register_number();
31 sttype_register_pointer();
32 sttype_register_set();
33 sttype_register_slice();
34 sttype_register_string();
35 sttype_register_opers();
46 sttype_register(sttype_t
*type
)
53 ws_assert(type_id
< STTYPE_NUM_TYPES
);
55 /* Don't re-register. */
56 ws_assert(type_list
[type_id
] == NULL
);
58 type_list
[type_id
] = type
;
62 sttype_lookup(sttype_id_t type_id
)
67 ws_assert(type_id
< STTYPE_NUM_TYPES
);
69 result
= type_list
[type_id
];
72 ws_assert(result
!= NULL
);
78 sttype_name(sttype_id_t type
)
81 case STTYPE_UNINITIALIZED
: return "UNINITIALIZED";
82 case STTYPE_TEST
: return "TEST";
83 case STTYPE_LITERAL
: return "LITERAL";
84 case STTYPE_UNPARSED
: return "UNPARSED";
85 case STTYPE_REFERENCE
: return "REFERENCE";
86 case STTYPE_STRING
: return "STRING";
87 case STTYPE_CHARCONST
: return "CHARCONST";
88 case STTYPE_NUMBER
: return "NUMBER";
89 case STTYPE_FIELD
: return "FIELD";
90 case STTYPE_FVALUE
: return "FVALUE";
91 case STTYPE_SLICE
: return "SLICE";
92 case STTYPE_FUNCTION
: return "FUNCTION";
93 case STTYPE_SET
: return "SET";
94 case STTYPE_PCRE
: return "PCRE";
95 case STTYPE_ARITHMETIC
: return "ARITHMETIC";
96 case STTYPE_NUM_TYPES
: return "NUM_TYPES";
98 return "(unknown sttype)";
102 stnode_op_name(stnode_op_t op
)
104 const char *s
= "(null)";
116 case STNODE_OP_ALL_EQ
:
119 case STNODE_OP_ANY_EQ
:
122 case STNODE_OP_ALL_NE
:
125 case STNODE_OP_ANY_NE
:
140 case STNODE_OP_BITWISE_AND
:
141 s
= "OP_BITWISE_AND";
143 case STNODE_OP_UNARY_MINUS
:
144 s
= "OP_UNARY_MINUS";
149 case STNODE_OP_SUBTRACT
:
152 case STNODE_OP_MULTIPLY
:
155 case STNODE_OP_DIVIDE
:
158 case STNODE_OP_MODULO
:
161 case STNODE_OP_CONTAINS
:
164 case STNODE_OP_MATCHES
:
170 case STNODE_OP_NOT_IN
:
173 case STNODE_OP_UNINITIALIZED
:
174 s
= "(uninitialized)";
182 stnode_clear(stnode_t
*node
)
185 if (node
->type
->func_free
&& node
->data
) {
186 node
->type
->func_free(node
->data
);
190 ws_assert(!node
->data
);
195 g_free(node
->repr_display
);
196 node
->repr_display
= NULL
;
197 g_free(node
->repr_debug
);
198 node
->repr_debug
= NULL
;
199 g_free(node
->repr_token
);
200 node
->repr_token
= NULL
;
201 node
->location
.col_start
= -1;
202 node
->location
.col_len
= 0;
207 stnode_init(stnode_t
*node
, sttype_id_t type_id
, void *data
, char *token
, df_loc_t loc
)
211 ws_assert(!node
->type
);
212 ws_assert(!node
->data
);
213 node
->repr_display
= NULL
;
214 node
->repr_debug
= NULL
;
215 node
->repr_token
= token
;
216 node
->location
= loc
;
219 if (type_id
== STTYPE_UNINITIALIZED
) {
224 /* Creating an initialized node with a NULL pointer is
225 * allowed and needs to be safe. The parser relies on that. */
226 type
= sttype_lookup(type_id
);
229 if (type
->func_new
) {
230 node
->data
= type
->func_new(data
);
239 stnode_replace(stnode_t
*node
, sttype_id_t type_id
, void *data
)
241 char *token
= g_strdup(node
->repr_token
);
242 df_loc_t loc
= node
->location
;
243 uint16_t flags
= node
->flags
;
245 stnode_init(node
, type_id
, data
, token
, loc
);
250 stnode_mutate(stnode_t
*node
, sttype_id_t type_id
)
252 //FIXME: Assert there all the same sttype
253 node
->type
= sttype_lookup(type_id
);
254 ws_assert(node
->type
);
258 stnode_new(sttype_id_t type_id
, void *data
, char *token
, df_loc_t loc
)
260 stnode_t
*node
= g_new0(stnode_t
, 1);
261 stnode_init(node
, type_id
, data
, token
, loc
);
266 stnode_new_empty(sttype_id_t type_id
)
268 df_loc_t loc
= {-1, 0};
269 return stnode_new(type_id
, NULL
, NULL
, loc
);
273 stnode_dup(const stnode_t
*node
)
277 new = g_new(stnode_t
, 1);
278 new->repr_display
= NULL
;
279 new->repr_debug
= NULL
;
280 new->repr_token
= g_strdup(node
->repr_token
);
281 new->location
= node
->location
;
282 new->flags
= node
->flags
;
284 new->type
= node
->type
;
285 if (node
->type
== NULL
)
287 else if (node
->type
->func_dup
)
288 new->data
= node
->type
->func_dup(node
->data
);
290 new->data
= node
->data
;
296 stnode_free(stnode_t
*node
)
303 stnode_type_name(stnode_t
*node
)
305 return sttype_name(node
->type
->id
);
309 stnode_type_id(stnode_t
*node
)
312 return node
->type
->id
;
314 return STTYPE_UNINITIALIZED
;
318 stnode_data(stnode_t
*node
)
324 stnode_string(stnode_t
*node
)
326 ws_assert(stnode_type_id(node
) == STTYPE_STRING
);
327 return stnode_data(node
);
331 stnode_steal_data(stnode_t
*node
)
333 void *data
= node
->data
;
340 stnode_token(stnode_t
*node
)
342 return node
->repr_token
;
346 stnode_location(stnode_t
*node
)
348 return node
->location
;
352 stnode_set_location(stnode_t
*node
, df_loc_t loc
)
354 node
->location
= loc
;
358 stnode_get_flags(stnode_t
*node
, uint16_t flags
)
360 return node
->flags
& flags
;
364 stnode_set_flags(stnode_t
*node
, uint16_t flags
)
366 node
->flags
|= flags
;
369 /* Finds the first and last location from a set and creates
370 * a new location from start of first (col_start) to end of
371 * last (col_start + col_len). Sets the result to dst. */
373 stnode_merge_location(stnode_t
*dst
, stnode_t
*n1
, stnode_t
*n2
)
375 df_loc_t first
, last
;
378 first
= last
= stnode_location(n1
);
379 loc2
= stnode_location(n2
);
380 if (loc2
.col_start
>= 0 && loc2
.col_start
> first
.col_start
)
382 dst
->location
.col_start
= first
.col_start
;
383 dst
->location
.col_len
= last
.col_start
- first
.col_start
+ last
.col_len
;
386 #define IS_OPERATOR(node) \
387 (stnode_type_id(node) == STTYPE_TEST || \
388 stnode_type_id(node) == STTYPE_ARITHMETIC)
391 _node_tostr(stnode_t
*node
, bool pretty
)
395 if (node
->type
->func_tostr
== NULL
)
396 s
= g_strdup("FIXME");
398 s
= node
->type
->func_tostr(node
->data
, pretty
);
403 if (IS_OPERATOR(node
)) {
407 repr
= ws_strdup_printf("%s(%s)", stnode_type_name(node
), s
);
415 stnode_tostr(stnode_t
*node
, bool pretty
)
417 if (pretty
&& IS_OPERATOR(node
) && node
->repr_token
!= NULL
) {
418 /* Some operators can have synonyms, like "or" and "||".
419 * Show the user the same representation as he typed. */
420 g_free(node
->repr_display
);
421 node
->repr_display
= g_strdup(node
->repr_token
);
422 return node
->repr_display
;
425 char *str
= _node_tostr(node
, pretty
);
428 g_free(node
->repr_display
);
429 node
->repr_display
= str
;
432 g_free(node
->repr_debug
);
433 node
->repr_debug
= str
;
440 sprint_node(stnode_t
*node
)
442 wmem_strbuf_t
*buf
= wmem_strbuf_new(NULL
, NULL
);
444 wmem_strbuf_append_printf(buf
, "{ ");
445 wmem_strbuf_append_printf(buf
, "type = %s, ", stnode_type_name(node
));
446 wmem_strbuf_append_printf(buf
, "data = %s, ", stnode_todebug(node
));
447 wmem_strbuf_append_printf(buf
, "location = %ld:%zu",
448 node
->location
.col_start
, node
->location
.col_len
);
449 wmem_strbuf_append_printf(buf
, " }");
450 return wmem_strbuf_finalize(buf
);
454 log_node_full(enum ws_log_level level
,
455 const char *file
, int line
, const char *func
,
456 stnode_t
*node
, const char *msg
)
458 if (!ws_log_msg_is_active(WS_LOG_DOMAIN
, level
))
462 ws_log_write_always_full(WS_LOG_DOMAIN
, level
,
463 file
, line
, func
, "%s is NULL", msg
);
467 char *str
= sprint_node(node
);
469 ws_log_write_always_full(WS_LOG_DOMAIN
, level
, file
, line
, func
,
470 "%s = %s", msg
, str
);
476 log_test_full(enum ws_log_level level
,
477 const char *file
, int line
, const char *func
,
478 stnode_t
*node
, const char *msg
)
480 if (!ws_log_msg_is_active(WS_LOG_DOMAIN
, level
))
484 ws_log_write_always_full(WS_LOG_DOMAIN
, level
,
485 file
, line
, func
, "%s is NULL", msg
);
490 stnode_t
*st_lhs
= NULL
, *st_rhs
= NULL
;
491 char *lhs
= NULL
, *rhs
= NULL
;
493 sttype_oper_get(node
, &st_op
, &st_lhs
, &st_rhs
);
496 lhs
= sprint_node(st_lhs
);
498 rhs
= sprint_node(st_rhs
);
500 ws_log_write_always_full(WS_LOG_DOMAIN
, level
, file
, line
, func
,
501 "%s:\n LHS = %s\n RHS = %s",
502 stnode_todebug(node
),
511 indent(wmem_strbuf_t
*buf
, int level
)
513 for (int i
= 0; i
< level
* 2; i
++) {
514 wmem_strbuf_append_c(buf
, ' ');
516 wmem_strbuf_append_printf(buf
, "% 2d ", level
);
520 visit_tree(wmem_strbuf_t
*buf
, stnode_t
*node
, int level
)
522 stnode_t
*left
, *right
;
523 stnode_t
*lower
, *upper
;
527 if (stnode_type_id(node
) == STTYPE_TEST
||
528 stnode_type_id(node
) == STTYPE_ARITHMETIC
) {
529 wmem_strbuf_append_printf(buf
, "%s:\n", stnode_todebug(node
));
530 sttype_oper_get(node
, NULL
, &left
, &right
);
532 indent(buf
, level
+ 1);
533 visit_tree(buf
, left
, level
+ 1);
534 wmem_strbuf_append_c(buf
, '\n');
535 indent(buf
, level
+ 1);
536 visit_tree(buf
, right
, level
+ 1);
539 indent(buf
, level
+ 1);
540 visit_tree(buf
, left
, level
+ 1);
543 ws_assert_not_reached();
546 else if (stnode_type_id(node
) == STTYPE_SET
) {
547 nodelist
= stnode_data(node
);
548 wmem_strbuf_append_printf(buf
, "SET(#%u):\n", g_slist_length(nodelist
) / 2);
550 indent(buf
, level
+ 1);
551 lower
= nodelist
->data
;
552 wmem_strbuf_append(buf
, stnode_tostr(lower
, false));
553 /* Set elements are always in pairs; upper may be null. */
554 nodelist
= g_slist_next(nodelist
);
556 upper
= nodelist
->data
;
558 wmem_strbuf_append(buf
, " .. ");
559 wmem_strbuf_append(buf
, stnode_tostr(upper
, false));
561 nodelist
= g_slist_next(nodelist
);
562 if (nodelist
!= NULL
) {
563 wmem_strbuf_append_c(buf
, '\n');
567 else if (stnode_type_id(node
) == STTYPE_FUNCTION
) {
568 wmem_strbuf_append_printf(buf
, "%s:\n", stnode_todebug(node
));
569 params
= sttype_function_params(node
);
571 indent(buf
, level
+ 1);
572 visit_tree(buf
, params
->data
, level
+ 1);
573 if (params
->next
!= NULL
) {
574 wmem_strbuf_append_c(buf
, '\n');
576 params
= params
->next
;
580 wmem_strbuf_append(buf
, stnode_todebug(node
));
585 dump_syntax_tree_str(stnode_t
*root
)
587 wmem_strbuf_t
*buf
= wmem_strbuf_new(NULL
, NULL
);
589 visit_tree(buf
, root
, 0);
590 return wmem_strbuf_finalize(buf
);
594 log_syntax_tree(enum ws_log_level level
, stnode_t
*root
, const char *msg
, char **cache_ptr
)
596 if (!ws_log_msg_is_active(LOG_DOMAIN_DFILTER
, level
))
599 char *str
= dump_syntax_tree_str(root
);
601 ws_log_write_always_full(LOG_DOMAIN_DFILTER
, level
, NULL
, -1, NULL
,
602 "%s:\n%s", msg
, str
);
613 * Editor modelines - https://www.wireshark.org/tools/modelines.html
618 * indent-tabs-mode: t
621 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
622 * :indentSize=8:tabSize=8:noTabs=false: