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
13 #include "syntax-tree.h"
14 #include "sttype-field.h"
15 #include "sttype-slice.h"
16 #include "sttype-op.h"
17 #include "sttype-set.h"
18 #include "sttype-function.h"
19 #include "ftypes/ftypes.h"
20 #include <wsutil/ws_assert.h>
23 fixup_jumps(void *data
, void *user_data
);
26 gencode(dfwork_t
*dfw
, stnode_t
*st_node
);
29 gen_entity(dfwork_t
*dfw
, stnode_t
*st_arg
, GSList
**jumps_ptr
);
32 select_opcode(dfvm_opcode_t op
, stmatch_t how
)
34 if (how
== STNODE_MATCH_DEF
)
44 case DFVM_ALL_CONTAINS
:
45 case DFVM_ALL_MATCHES
:
47 case DFVM_SET_ALL_NOT_IN
:
48 return how
== STNODE_MATCH_ALL
? op
: op
+ 1;
55 case DFVM_ANY_CONTAINS
:
56 case DFVM_ANY_MATCHES
:
58 case DFVM_SET_ANY_NOT_IN
:
59 return how
== STNODE_MATCH_ANY
? op
: op
- 1;
61 ASSERT_DFVM_OP_NOT_REACHED(op
);
63 ws_assert_not_reached();
67 dfw_append_insn(dfwork_t
*dfw
, dfvm_insn_t
*insn
)
69 insn
->id
= dfw
->next_insn_id
;
71 g_ptr_array_add(dfw
->insns
, insn
);
75 dfw_append_stack_push(dfwork_t
*dfw
, dfvm_value_t
*arg1
)
79 insn
= dfvm_insn_new(DFVM_STACK_PUSH
);
80 insn
->arg1
= dfvm_value_ref(arg1
);
81 dfw_append_insn(dfw
, insn
);
85 dfw_append_stack_pop(dfwork_t
*dfw
, unsigned count
)
90 insn
= dfvm_insn_new(DFVM_STACK_POP
);
91 val
= dfvm_value_new_uint(count
);
92 insn
->arg1
= dfvm_value_ref(val
);
93 dfw_append_insn(dfw
, insn
);
97 dfw_append_set_add_range(dfwork_t
*dfw
, dfvm_value_t
*arg1
, dfvm_value_t
*arg2
)
101 insn
= dfvm_insn_new(DFVM_SET_ADD_RANGE
);
102 insn
->arg1
= dfvm_value_ref(arg1
);
103 insn
->arg2
= dfvm_value_ref(arg2
);
104 dfw_append_insn(dfw
, insn
);
108 dfw_append_set_add(dfwork_t
*dfw
, dfvm_value_t
*arg1
)
112 insn
= dfvm_insn_new(DFVM_SET_ADD
);
113 insn
->arg1
= dfvm_value_ref(arg1
);
114 dfw_append_insn(dfw
, insn
);
117 static dfvm_value_t
*
118 dfw_append_jump(dfwork_t
*dfw
)
123 insn
= dfvm_insn_new(DFVM_IF_FALSE_GOTO
);
124 jmp
= dfvm_value_new(INSN_NUMBER
);
125 insn
->arg1
= dfvm_value_ref(jmp
);
126 dfw_append_insn(dfw
, insn
);
130 /* returns register number */
131 static dfvm_value_t
*
132 dfw_append_read_tree(dfwork_t
*dfw
, header_field_info
*hfinfo
,
138 dfvm_value_t
*reg_val
, *val1
, *val3
;
139 bool added_new_hfinfo
= false;
140 GHashTable
*loaded_fields
;
143 /* Rewind to find the first field of this name. */
144 while (hfinfo
->same_name_prev_id
!= -1) {
145 hfinfo
= proto_registrar_get_nth(hfinfo
->same_name_prev_id
);
149 loaded_fields
= dfw
->loaded_raw_fields
;
151 loaded_fields
= dfw
->loaded_fields
;
153 /* Keep track of which registers
154 * were used for which hfinfo's so that we
155 * can re-use registers. */
156 /* Re-use only if we are not using a range (layer filter). */
157 loaded_key
= g_hash_table_lookup(loaded_fields
, hfinfo
);
158 if (loaded_key
!= NULL
) {
161 * Reg's are stored in has as reg+1, so
162 * that the non-existence of a hfinfo in
163 * the hash, or 0, can be differentiated from
164 * a hfinfo being loaded into register #0.
166 reg
= GPOINTER_TO_INT(loaded_key
) - 1;
169 reg
= dfw
->next_register
++;
173 reg
= dfw
->next_register
++;
174 g_hash_table_insert(loaded_fields
,
175 hfinfo
, GINT_TO_POINTER(reg
+ 1));
177 added_new_hfinfo
= true;
180 val1
= dfvm_value_new_hfinfo(hfinfo
, raw
);
181 reg_val
= dfvm_value_new_register(reg
);
183 val3
= dfvm_value_new_drange(range
);
184 insn
= dfvm_insn_new(DFVM_READ_TREE_R
);
188 insn
= dfvm_insn_new(DFVM_READ_TREE
);
190 insn
->arg1
= dfvm_value_ref(val1
);
191 insn
->arg2
= dfvm_value_ref(reg_val
);
192 insn
->arg3
= dfvm_value_ref(val3
);
193 dfw_append_insn(dfw
, insn
);
195 if (added_new_hfinfo
) {
197 /* Record the FIELD_ID in hash of interesting fields. */
198 g_hash_table_add(dfw
->interesting_fields
, &hfinfo
->id
);
199 hfinfo
= hfinfo
->same_name_next
;
206 /* returns register number */
207 static dfvm_value_t
*
208 dfw_append_read_reference(dfwork_t
*dfw
, header_field_info
*hfinfo
,
213 dfvm_value_t
*reg_val
, *val1
, *val3
;
214 GPtrArray
*refs_array
;
216 /* Rewind to find the first field of this name. */
217 while (hfinfo
->same_name_prev_id
!= -1) {
218 hfinfo
= proto_registrar_get_nth(hfinfo
->same_name_prev_id
);
221 /* We can't reuse registers with a filter so just skip
222 * that optimization and don't reuse them at all. */
223 val1
= dfvm_value_new_hfinfo(hfinfo
, raw
);
224 reg_val
= dfvm_value_new_register(dfw
->next_register
++);
226 val3
= dfvm_value_new_drange(range
);
227 insn
= dfvm_insn_new(DFVM_READ_REFERENCE_R
);
231 insn
= dfvm_insn_new(DFVM_READ_REFERENCE
);
233 insn
->arg1
= dfvm_value_ref(val1
);
234 insn
->arg2
= dfvm_value_ref(reg_val
);
235 insn
->arg3
= dfvm_value_ref(val3
);
236 dfw_append_insn(dfw
, insn
);
238 refs_array
= g_ptr_array_new_with_free_func((GDestroyNotify
)reference_free
);
240 g_hash_table_insert(dfw
->raw_references
, hfinfo
, refs_array
);
242 g_hash_table_insert(dfw
->references
, hfinfo
, refs_array
);
244 /* Record the FIELD_ID in hash of interesting fields. */
246 /* Record the FIELD_ID in hash of interesting fields. */
247 g_hash_table_add(dfw
->interesting_fields
, &hfinfo
->id
);
248 hfinfo
= hfinfo
->same_name_next
;
254 /* returns register number */
255 static dfvm_value_t
*
256 dfw_append_mk_slice(dfwork_t
*dfw
, stnode_t
*node
, GSList
**jumps_ptr
)
260 dfvm_value_t
*reg_val
, *val1
, *val3
;
262 entity
= sttype_slice_entity(node
);
264 insn
= dfvm_insn_new(DFVM_SLICE
);
265 val1
= gen_entity(dfw
, entity
, jumps_ptr
);
266 insn
->arg1
= dfvm_value_ref(val1
);
267 reg_val
= dfvm_value_new_register(dfw
->next_register
++);
268 insn
->arg2
= dfvm_value_ref(reg_val
);
269 val3
= dfvm_value_new_drange(sttype_slice_drange_steal(node
));
270 insn
->arg3
= dfvm_value_ref(val3
);
271 sttype_slice_remove_drange(node
);
272 dfw_append_insn(dfw
, insn
);
277 /* Returns register number. This applies the value string in hfinfo to the
278 * contents of the src register. */
279 static dfvm_value_t
*
280 dfw_append_mk_value_string(dfwork_t
*dfw
, stnode_t
*node
, dfvm_value_t
*src
)
283 dfvm_value_t
*reg_val
, *val1
;
285 insn
= dfvm_insn_new(DFVM_VALUE_STRING
);
286 val1
= dfvm_value_new_hfinfo(sttype_field_hfinfo(node
), false);
287 insn
->arg1
= dfvm_value_ref(val1
);
288 insn
->arg2
= dfvm_value_ref(src
);
289 reg_val
= dfvm_value_new_register(dfw
->next_register
++);
290 insn
->arg3
= dfvm_value_ref(reg_val
);
291 dfw_append_insn(dfw
, insn
);
296 /* returns register number */
297 _U_
static dfvm_value_t
*
298 dfw_append_put_fvalue(dfwork_t
*dfw
, fvalue_t
*fv
)
301 dfvm_value_t
*reg_val
, *val1
;
303 insn
= dfvm_insn_new(DFVM_PUT_FVALUE
);
304 val1
= dfvm_value_new_fvalue(fv
);
305 insn
->arg1
= dfvm_value_ref(val1
);
306 reg_val
= dfvm_value_new_register(dfw
->next_register
++);
307 insn
->arg2
= dfvm_value_ref(reg_val
);
308 dfw_append_insn(dfw
, insn
);
313 /* returns register number that the length's result will be in. */
314 static dfvm_value_t
*
315 dfw_append_length(dfwork_t
*dfw
, stnode_t
*node
, GSList
**jumps_ptr
)
319 dfvm_value_t
*reg_val
, *val_arg
;
321 /* Create the new DFVM instruction */
322 insn
= dfvm_insn_new(DFVM_LENGTH
);
323 /* Create input argument */
324 params
= sttype_function_params(node
);
326 ws_assert(g_slist_length(params
) == 1);
327 val_arg
= gen_entity(dfw
, params
->data
, jumps_ptr
);
328 insn
->arg1
= dfvm_value_ref(val_arg
);
330 reg_val
= dfvm_value_new_register(dfw
->next_register
++);
331 insn
->arg2
= dfvm_value_ref(reg_val
);
333 dfw_append_insn(dfw
, insn
);
337 /* returns register number that the value string result will be in. */
338 static dfvm_value_t
*
339 dfw_append_value_string(dfwork_t
*dfw
, stnode_t
*node
, GSList
**jumps_ptr
)
343 params
= sttype_function_params(node
);
345 ws_assert(g_slist_length(params
) == 1);
346 return gen_entity(dfw
, params
->data
, jumps_ptr
);
349 /* returns register number that the functions's result will be in. */
350 static dfvm_value_t
*
351 dfw_append_function(dfwork_t
*dfw
, stnode_t
*node
, GSList
**jumps_ptr
)
356 dfvm_value_t
*reg_val
, *val1
, *val3
, *val_arg
;
359 GSList
*params_jumps
= NULL
;
361 func
= sttype_function_funcdef(node
);
363 if (strcmp(func
->name
, "len") == 0) {
364 /* Replace len() function call with DFVM_LENGTH instruction. */
365 return dfw_append_length(dfw
, node
, jumps_ptr
);
368 if (strcmp(func
->name
, "vals") == 0) {
369 /* Replace vals() function call with DFVM_VALUE_STRING instruction. */
370 return dfw_append_value_string(dfw
, node
, jumps_ptr
);
373 /* Create the new DFVM instruction */
374 insn
= dfvm_insn_new(DFVM_CALL_FUNCTION
);
375 val1
= dfvm_value_new_funcdef(func
);
376 insn
->arg1
= dfvm_value_ref(val1
);
377 reg_val
= dfvm_value_new_register(dfw
->next_register
++);
378 insn
->arg2
= dfvm_value_ref(reg_val
);
380 /* Create input arguments */
381 params
= sttype_function_params(node
);
385 val_arg
= gen_entity(dfw
, params
->data
, ¶ms_jumps
);
386 /* If a parameter fails to generate jump here.
387 * Note: stack_push NULL register is valid. */
388 g_slist_foreach(params_jumps
, fixup_jumps
, dfw
);
389 g_slist_free(params_jumps
);
391 dfw_append_stack_push(dfw
, val_arg
);
393 params
= params
->next
;
395 val3
= dfvm_value_new_uint(count
);
396 insn
->arg3
= dfvm_value_ref(val3
);
397 dfw_append_insn(dfw
, insn
);
398 dfw_append_stack_pop(dfw
, count
);
400 /* We need another instruction to jump to another exit
401 * place, if the call() of our function failed for some reason */
402 insn
= dfvm_insn_new(DFVM_IF_FALSE_GOTO
);
403 jmp
= dfvm_value_new(INSN_NUMBER
);
404 insn
->arg1
= dfvm_value_ref(jmp
);
405 dfw_append_insn(dfw
, insn
);
406 *jumps_ptr
= g_slist_prepend(*jumps_ptr
, jmp
);
412 * Adds an instruction for a relation operator where the values are already
413 * loaded in registers.
416 gen_relation_insn(dfwork_t
*dfw
, dfvm_opcode_t op
,
417 dfvm_value_t
*arg1
, dfvm_value_t
*arg2
,
422 insn
= dfvm_insn_new(op
);
423 insn
->arg1
= dfvm_value_ref(arg1
);
424 insn
->arg2
= dfvm_value_ref(arg2
);
425 insn
->arg3
= dfvm_value_ref(arg3
);
426 dfw_append_insn(dfw
, insn
);
430 gen_relation(dfwork_t
*dfw
, dfvm_opcode_t op
, stmatch_t how
,
431 stnode_t
*st_arg1
, stnode_t
*st_arg2
)
433 GSList
*jumps
= NULL
;
434 dfvm_value_t
*val1
, *val2
;
436 /* Create code for the LHS and RHS of the relation */
437 val1
= gen_entity(dfw
, st_arg1
, &jumps
);
438 val2
= gen_entity(dfw
, st_arg2
, &jumps
);
440 /* Then combine them in a DFVM instruction */
441 op
= select_opcode(op
, how
);
442 gen_relation_insn(dfw
, op
, val1
, val2
, NULL
);
444 /* If either of the relation arguments need an "exit" instruction
445 * to jump to (on failure), mark them */
446 g_slist_foreach(jumps
, fixup_jumps
, dfw
);
452 fixup_jumps(void *data
, void *user_data
)
454 dfvm_value_t
*jmp
= (dfvm_value_t
*)data
;
455 dfwork_t
*dfw
= (dfwork_t
*)user_data
;
458 jmp
->value
.numeric
= dfw
->next_insn_id
;
462 /* Generate the code for the in operator. Pushes set values into a stack
463 * and then evaluates membership in a single instruction. */
465 gen_relation_in(dfwork_t
*dfw
, dfvm_opcode_t op
, stmatch_t how
,
466 stnode_t
*st_arg1
, stnode_t
*st_arg2
)
469 GSList
*jumps
= NULL
;
470 GSList
*node_jumps
= NULL
;
471 dfvm_value_t
*val1
, *val2
, *val3
;
472 stnode_t
*node1
, *node2
;
473 GSList
*nodelist_head
, *nodelist
;
475 /* Create code for the LHS of the relation */
476 val1
= gen_entity(dfw
, st_arg1
, &jumps
);
478 /* Create code to populate the set stack */
479 nodelist_head
= nodelist
= stnode_steal_data(st_arg2
);
481 node1
= nodelist
->data
;
482 nodelist
= g_slist_next(nodelist
);
483 node2
= nodelist
->data
;
484 nodelist
= g_slist_next(nodelist
);
488 val2
= gen_entity(dfw
, node1
, &node_jumps
);
489 val3
= gen_entity(dfw
, node2
, &node_jumps
);
490 dfw_append_set_add_range(dfw
, val2
, val3
);
492 /* Normal element. */
493 val2
= gen_entity(dfw
, node1
, &node_jumps
);
494 dfw_append_set_add(dfw
, val2
);
497 /* If an item is not present, just jump to the next item */
498 g_slist_foreach(node_jumps
, fixup_jumps
, dfw
);
499 g_slist_free(node_jumps
);
502 set_nodelist_free(nodelist_head
);
504 /* Create code for the set on the RHS of the relation */
505 insn
= dfvm_insn_new(select_opcode(op
, how
));
506 insn
->arg1
= dfvm_value_ref(val1
);
507 dfw_append_insn(dfw
, insn
);
509 /* Add instruction to clear the whole stack */
510 insn
= dfvm_insn_new(DFVM_SET_CLEAR
);
511 dfw_append_insn(dfw
, insn
);
513 /* Jump here if the LHS entity was not present */
514 g_slist_foreach(jumps
, fixup_jumps
, dfw
);
519 static dfvm_value_t
*
520 gen_arithmetic(dfwork_t
*dfw
, stnode_t
*st_arg
, GSList
**jumps_ptr
)
522 stnode_t
*left
, *right
;
524 dfvm_value_t
*reg_val
, *val1
, *val2
= NULL
;
525 dfvm_opcode_t op
= DFVM_NULL
;
527 sttype_oper_get(st_arg
, &st_op
, &left
, &right
);
530 case STNODE_OP_UNARY_MINUS
: op
= DFVM_UNARY_MINUS
; break;
531 case STNODE_OP_ADD
: op
= DFVM_ADD
; break;
532 case STNODE_OP_SUBTRACT
: op
= DFVM_SUBTRACT
; break;
533 case STNODE_OP_MULTIPLY
: op
= DFVM_MULTIPLY
; break;
534 case STNODE_OP_DIVIDE
: op
= DFVM_DIVIDE
; break;
535 case STNODE_OP_MODULO
: op
= DFVM_MODULO
; break;
536 case STNODE_OP_BITWISE_AND
: op
= DFVM_BITWISE_AND
; break;
542 case STNODE_OP_ALL_EQ
:
543 case STNODE_OP_ANY_EQ
:
544 case STNODE_OP_ALL_NE
:
545 case STNODE_OP_ANY_NE
:
550 case STNODE_OP_CONTAINS
:
551 case STNODE_OP_MATCHES
:
553 case STNODE_OP_NOT_IN
:
554 case STNODE_OP_UNINITIALIZED
:
555 ASSERT_STNODE_OP_NOT_REACHED(st_op
);
558 val1
= gen_entity(dfw
, left
, jumps_ptr
);
560 /* Generate unary DFVM instruction. */
561 reg_val
= dfvm_value_new_register(dfw
->next_register
++);
562 gen_relation_insn(dfw
, op
, val1
, reg_val
, NULL
);
566 val2
= gen_entity(dfw
, right
, jumps_ptr
);
567 reg_val
= dfvm_value_new_register(dfw
->next_register
++);
568 gen_relation_insn(dfw
, op
, val1
, val2
, reg_val
);
572 /* Parse an entity, returning the reg that it gets put into.
573 * p_jmp will be set if it has to be set by the calling code; it should
574 * be set to the place to jump to, to return to the calling code,
575 * if the load of a field from the proto_tree fails. */
576 static dfvm_value_t
*
577 gen_entity(dfwork_t
*dfw
, stnode_t
*st_arg
, GSList
**jumps_ptr
)
581 header_field_info
*hfinfo
;
582 drange_t
*range
= NULL
;
584 e_type
= stnode_type_id(st_arg
);
586 if (e_type
== STTYPE_FIELD
) {
587 hfinfo
= sttype_field_hfinfo(st_arg
);
588 range
= sttype_field_drange_steal(st_arg
);
589 raw
= sttype_field_raw(st_arg
);
590 val
= dfw_append_read_tree(dfw
, hfinfo
, range
, raw
);
591 if (jumps_ptr
!= NULL
) {
592 *jumps_ptr
= g_slist_prepend(*jumps_ptr
, dfw_append_jump(dfw
));
594 if (sttype_field_value_string(st_arg
)) {
595 val
= dfw_append_mk_value_string(dfw
, st_arg
, val
);
596 if (jumps_ptr
!= NULL
) {
597 *jumps_ptr
= g_slist_prepend(*jumps_ptr
, dfw_append_jump(dfw
));
601 else if (e_type
== STTYPE_REFERENCE
) {
602 hfinfo
= sttype_field_hfinfo(st_arg
);
603 range
= sttype_field_drange_steal(st_arg
);
604 raw
= sttype_field_raw(st_arg
);
605 val
= dfw_append_read_reference(dfw
, hfinfo
, range
, raw
);
606 if (jumps_ptr
!= NULL
) {
607 *jumps_ptr
= g_slist_prepend(*jumps_ptr
, dfw_append_jump(dfw
));
609 if (sttype_field_value_string(st_arg
)) {
610 val
= dfw_append_mk_value_string(dfw
, st_arg
, val
);
611 if (jumps_ptr
!= NULL
) {
612 *jumps_ptr
= g_slist_prepend(*jumps_ptr
, dfw_append_jump(dfw
));
616 else if (e_type
== STTYPE_FVALUE
) {
617 val
= dfvm_value_new_fvalue(stnode_steal_data(st_arg
));
619 else if (e_type
== STTYPE_SLICE
) {
620 val
= dfw_append_mk_slice(dfw
, st_arg
, jumps_ptr
);
622 else if (e_type
== STTYPE_FUNCTION
) {
623 val
= dfw_append_function(dfw
, st_arg
, jumps_ptr
);
625 else if (e_type
== STTYPE_PCRE
) {
626 val
= dfvm_value_new_pcre(stnode_steal_data(st_arg
));
628 else if (e_type
== STTYPE_ARITHMETIC
) {
629 val
= gen_arithmetic(dfw
, st_arg
, jumps_ptr
);
632 ws_error("Invalid sttype: %s", stnode_type_name(st_arg
));
638 gen_exists(dfwork_t
*dfw
, stnode_t
*st_node
)
641 dfvm_value_t
*val1
, *val2
= NULL
;
642 header_field_info
*hfinfo
;
643 drange_t
*range
= NULL
;
645 hfinfo
= sttype_field_hfinfo(st_node
);
646 range
= sttype_field_drange_steal(st_node
);
648 /* Rewind to find the first field of this name. */
649 while (hfinfo
->same_name_prev_id
!= -1) {
650 hfinfo
= proto_registrar_get_nth(hfinfo
->same_name_prev_id
);
653 /* Ignore "rawness" for existence tests. */
654 val1
= dfvm_value_new_hfinfo(hfinfo
, false);
656 val2
= dfvm_value_new_drange(range
);
660 insn
= dfvm_insn_new(DFVM_CHECK_EXISTS_R
);
661 insn
->arg1
= dfvm_value_ref(val1
);
662 insn
->arg2
= dfvm_value_ref(val2
);
665 insn
= dfvm_insn_new(DFVM_CHECK_EXISTS
);
666 insn
->arg1
= dfvm_value_ref(val1
);
668 dfw_append_insn(dfw
, insn
);
670 /* Record the FIELD_ID in hash of interesting fields. */
672 g_hash_table_add(dfw
->interesting_fields
, &hfinfo
->id
);
673 hfinfo
= hfinfo
->same_name_next
;
678 gen_field(dfwork_t
*dfw
, stnode_t
*st_node
)
681 GSList
*jumps
= NULL
;
683 val1
= gen_entity(dfw
, st_node
, &jumps
);
684 g_slist_foreach(jumps
, fixup_jumps
, dfw
);
690 gen_notzero(dfwork_t
*dfw
, stnode_t
*st_node
)
694 GSList
*jumps
= NULL
;
696 val1
= gen_entity(dfw
, st_node
, &jumps
);
697 insn
= dfvm_insn_new(DFVM_NOT_ALL_ZERO
);
698 insn
->arg1
= dfvm_value_ref(val1
);
699 dfw_append_insn(dfw
, insn
);
700 g_slist_foreach(jumps
, fixup_jumps
, dfw
);
706 gen_notzero_slice(dfwork_t
*dfw
, stnode_t
*st_node
)
709 dfvm_value_t
*val1
, *reg_val
;
710 GSList
*jumps
= NULL
;
712 val1
= gen_entity(dfw
, st_node
, &jumps
);
713 /* Compute length. */
714 insn
= dfvm_insn_new(DFVM_LENGTH
);
715 insn
->arg1
= dfvm_value_ref(val1
);
716 reg_val
= dfvm_value_new_register(dfw
->next_register
++);
717 insn
->arg2
= dfvm_value_ref(reg_val
);
718 dfw_append_insn(dfw
, insn
);
719 /* Check length is not zero. */
720 insn
= dfvm_insn_new(DFVM_NOT_ALL_ZERO
);
721 insn
->arg1
= dfvm_value_ref(reg_val
);
722 dfw_append_insn(dfw
, insn
);
724 g_slist_foreach(jumps
, fixup_jumps
, dfw
);
730 gen_test(dfwork_t
*dfw
, stnode_t
*st_node
)
734 stnode_t
*st_arg1
, *st_arg2
;
739 sttype_oper_get(st_node
, &st_op
, &st_arg1
, &st_arg2
);
740 st_how
= sttype_test_get_match(st_node
);
744 gencode(dfw
, st_arg1
);
745 insn
= dfvm_insn_new(DFVM_NOT
);
746 dfw_append_insn(dfw
, insn
);
750 gencode(dfw
, st_arg1
);
752 insn
= dfvm_insn_new(DFVM_IF_FALSE_GOTO
);
753 jmp
= dfvm_value_new(INSN_NUMBER
);
754 insn
->arg1
= dfvm_value_ref(jmp
);
755 dfw_append_insn(dfw
, insn
);
757 gencode(dfw
, st_arg2
);
758 jmp
->value
.numeric
= dfw
->next_insn_id
;
762 gencode(dfw
, st_arg1
);
764 insn
= dfvm_insn_new(DFVM_IF_TRUE_GOTO
);
765 jmp
= dfvm_value_new(INSN_NUMBER
);
766 insn
->arg1
= dfvm_value_ref(jmp
);
767 dfw_append_insn(dfw
, insn
);
769 gencode(dfw
, st_arg2
);
770 jmp
->value
.numeric
= dfw
->next_insn_id
;
773 case STNODE_OP_ALL_EQ
:
774 gen_relation(dfw
, DFVM_ALL_EQ
, st_how
, st_arg1
, st_arg2
);
777 case STNODE_OP_ANY_EQ
:
778 gen_relation(dfw
, DFVM_ANY_EQ
, st_how
, st_arg1
, st_arg2
);
781 case STNODE_OP_ALL_NE
:
782 gen_relation(dfw
, DFVM_ALL_NE
, st_how
, st_arg1
, st_arg2
);
785 case STNODE_OP_ANY_NE
:
786 gen_relation(dfw
, DFVM_ANY_NE
, st_how
, st_arg1
, st_arg2
);
790 gen_relation(dfw
, DFVM_ANY_GT
, st_how
, st_arg1
, st_arg2
);
794 gen_relation(dfw
, DFVM_ANY_GE
, st_how
, st_arg1
, st_arg2
);
798 gen_relation(dfw
, DFVM_ANY_LT
, st_how
, st_arg1
, st_arg2
);
802 gen_relation(dfw
, DFVM_ANY_LE
, st_how
, st_arg1
, st_arg2
);
805 case STNODE_OP_CONTAINS
:
806 gen_relation(dfw
, DFVM_ANY_CONTAINS
, st_how
, st_arg1
, st_arg2
);
809 case STNODE_OP_MATCHES
:
810 gen_relation(dfw
, DFVM_ANY_MATCHES
, st_how
, st_arg1
, st_arg2
);
814 gen_relation_in(dfw
, DFVM_SET_ANY_IN
, st_how
, st_arg1
, st_arg2
);
817 case STNODE_OP_NOT_IN
:
818 gen_relation_in(dfw
, DFVM_SET_ANY_NOT_IN
, st_how
, st_arg1
, st_arg2
);
821 case STNODE_OP_UNINITIALIZED
:
822 case STNODE_OP_BITWISE_AND
:
823 case STNODE_OP_UNARY_MINUS
:
825 case STNODE_OP_SUBTRACT
:
826 case STNODE_OP_MULTIPLY
:
827 case STNODE_OP_DIVIDE
:
828 case STNODE_OP_MODULO
:
829 ASSERT_STNODE_OP_NOT_REACHED(st_op
);
834 gencode(dfwork_t
*dfw
, stnode_t
*st_node
)
836 dfvm_value_t
* val
= NULL
;
837 /* If the root of the tree is a field, load and return the
838 * values if we were asked to do so. If not, or anywhere
839 * other than the root, just test for existence.
841 bool return_val
= dfw
->flags
& DF_RETURN_VALUES
;
842 dfw
->flags
&= ~DF_RETURN_VALUES
;
843 switch (stnode_type_id(st_node
)) {
845 gen_test(dfw
, st_node
);
849 val
= gen_field(dfw
, st_node
);
851 gen_exists(dfw
, st_node
);
854 case STTYPE_ARITHMETIC
:
855 case STTYPE_FUNCTION
:
856 val
= gen_notzero(dfw
, st_node
);
859 val
= gen_notzero_slice(dfw
, st_node
);
862 ASSERT_STTYPE_NOT_REACHED(stnode_type_id(st_node
));
869 optimize(dfwork_t
*dfw
)
872 dfvm_insn_t
*insn
, *insn1
, *prev
;
875 length
= dfw
->insns
->len
;
877 for (id
= 0, prev
= NULL
; id
< length
; prev
= insn
, id
++) {
878 insn
= (dfvm_insn_t
*)g_ptr_array_index(dfw
->insns
, id
);
880 if (insn
->op
== DFVM_IF_TRUE_GOTO
|| insn
->op
== DFVM_IF_FALSE_GOTO
) {
881 id1
= arg1
->value
.numeric
;
883 /* If the branch jumps to the next instruction replace it with a no-op. */
885 dfvm_insn_replace_no_op(insn
);
889 /* Try to optimize branch jumps */
890 dfvm_opcode_t revert
= (insn
->op
== DFVM_IF_FALSE_GOTO
) ? DFVM_IF_TRUE_GOTO
: DFVM_IF_FALSE_GOTO
;
892 insn1
= (dfvm_insn_t
*)g_ptr_array_index(dfw
->insns
, id1
);
893 if (insn1
->op
== revert
) {
894 /* Skip this one; it is always false and the branch is not taken */
898 if (insn1
->op
== DFVM_READ_TREE
&& prev
&& prev
->op
== DFVM_READ_TREE
&&
899 prev
->arg2
->value
.numeric
== insn1
->arg2
->value
.numeric
) {
900 /* Skip this one; hack if it's the same register it's the same field
901 * and it returns the same value */
905 if (insn1
->op
== insn
->op
) {
906 /* The branch jumps to the same branch instruction so
907 * coalesce the jumps */
909 id1
= arg1
->value
.numeric
;
914 arg1
->value
.numeric
= id1
;
922 dfw_gencode(dfwork_t
*dfw
)
924 dfw
->insns
= g_ptr_array_new();
925 dfw
->loaded_fields
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
926 dfw
->loaded_raw_fields
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
927 dfw
->interesting_fields
= g_hash_table_new(g_int_hash
, g_int_equal
);
928 dfvm_insn_t
*insn
= dfvm_insn_new(DFVM_RETURN
);
929 insn
->arg1
= dfvm_value_ref(gencode(dfw
, dfw
->st_root
));
930 dfw_append_insn(dfw
, insn
);
931 if (dfw
->flags
& DF_OPTIMIZE
) {
943 get_hash_key(void *key
, void *value _U_
, void *user_data
)
945 int field_id
= *(int *)key
;
946 hash_key_iterator
*hki
= (hash_key_iterator
*)user_data
;
948 hki
->fields
[hki
->i
] = field_id
;
953 dfw_interesting_fields(dfwork_t
*dfw
, int *caller_num_fields
)
955 int num_fields
= g_hash_table_size(dfw
->interesting_fields
);
957 hash_key_iterator hki
;
959 if (num_fields
== 0) {
960 *caller_num_fields
= 0;
964 hki
.fields
= g_new(int, num_fields
);
967 g_hash_table_foreach(dfw
->interesting_fields
, get_hash_key
, &hki
);
968 *caller_num_fields
= num_fields
;
973 * Editor modelines - https://www.wireshark.org/tools/modelines.html
978 * indent-tabs-mode: t
981 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
982 * :indentSize=8:tabSize=8:noTabs=false: