diff options
Diffstat (limited to 'epan/dfilter/gencode.c')
-rw-r--r-- | epan/dfilter/gencode.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/epan/dfilter/gencode.c b/epan/dfilter/gencode.c new file mode 100644 index 0000000000..61c5546cb6 --- /dev/null +++ b/epan/dfilter/gencode.c @@ -0,0 +1,299 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dfilter-int.h" +#include "dfvm.h" +#include "syntax-tree.h" +#include "sttype-range.h" +#include "sttype-test.h" +#include "ftypes/ftypes.h" +#include "gdebug.h" + +static void +gencode(dfwork_t *dfw, stnode_t *st_node); + +static void +dfw_append_insn(dfwork_t *dfw, dfvm_insn_t *insn) +{ + insn->id = dfw->next_insn_id; + dfw->next_insn_id++; + g_ptr_array_add(dfw->insns, insn); +} + +/* returns register number */ +static int +dfw_append_read_tree(dfwork_t *dfw, int field_id) +{ + dfvm_insn_t *insn; + dfvm_value_t *val1, *val2; + int reg = -1; + + /* Keep track of which registers + * were used for which field_id's so that we + * can re-use registers. */ + reg = GPOINTER_TO_UINT( + g_hash_table_lookup(dfw->loaded_fields, + GUINT_TO_POINTER(field_id))); + if (reg) { + /* Reg's are stored in has as reg+1, so + * that the non-existence of a field_id in + * the hash, or 0, can be differentiated from + * a field_id being loaded into register #0. */ + reg--; + } + else { + reg = dfw->next_register++; + g_hash_table_insert(dfw->loaded_fields, + GUINT_TO_POINTER(field_id), + GUINT_TO_POINTER(reg + 1)); + } + + insn = dfvm_insn_new(READ_TREE); + val1 = dfvm_value_new(FIELD_ID); + val1->value.numeric = field_id; + val2 = dfvm_value_new(REGISTER); + val2->value.numeric = reg; + + insn->arg1 = val1; + insn->arg2 = val2; + dfw_append_insn(dfw, insn); + + return reg; +} + +/* returns register number */ +static int +dfw_append_put_fvalue(dfwork_t *dfw, fvalue_t *fv) +{ + dfvm_insn_t *insn; + dfvm_value_t *val1, *val2; + int reg; + + insn = dfvm_insn_new(PUT_FVALUE); + val1 = dfvm_value_new(FVALUE); + val1->value.fvalue = fv; + val2 = dfvm_value_new(REGISTER); + reg = dfw->next_register++; + val2->value.numeric = reg; + insn->arg1 = val1; + insn->arg2 = val2; + dfw_append_insn(dfw, insn); + + return reg; +} + +/* returns register number */ +static int +dfw_append_mk_range(dfwork_t *dfw, stnode_t *node) +{ + int hf_reg, reg; + header_field_info *hfinfo; + dfvm_insn_t *insn; + dfvm_value_t *val; + + hfinfo = sttype_range_hfinfo(node); + hf_reg = dfw_append_read_tree(dfw, hfinfo->id); + + insn = dfvm_insn_new(MK_RANGE); + + val = dfvm_value_new(REGISTER); + val->value.numeric = hf_reg; + insn->arg1 = val; + + val = dfvm_value_new(REGISTER); + reg =dfw->next_register++; + val->value.numeric = reg; + insn->arg2 = val; + + val = dfvm_value_new(INTEGER); + val->value.numeric = sttype_range_start(node); + insn->arg3 = val; + + val = dfvm_value_new(INTEGER); + val->value.numeric = sttype_range_end(node); + insn->arg4 = val; + + dfw_append_insn(dfw, insn); + + return reg; +} + + +static void +gen_relation(dfwork_t *dfw, dfvm_opcode_t op, stnode_t *st_arg1, stnode_t *st_arg2) +{ + sttype_id_t type1, type2; + dfvm_insn_t *insn; + dfvm_value_t *val1, *val2; + dfvm_value_t *jmp1 = NULL, *jmp2 = NULL; + int reg1 = -1, reg2 = -1; + header_field_info *hfinfo; + + fvalue_t *junk = NULL; + + type1 = stnode_type_id(st_arg1); + type2 = stnode_type_id(st_arg2); + + if (type1 == STTYPE_FIELD) { + hfinfo = stnode_data(st_arg1); + reg1 = dfw_append_read_tree(dfw, hfinfo->id); + + insn = dfvm_insn_new(IF_FALSE_GOTO); + jmp1 = dfvm_value_new(INSN_NUMBER); + insn->arg1 = jmp1; + dfw_append_insn(dfw, insn); + } + else if (type1 == STTYPE_FVALUE) { + reg1 = dfw_append_put_fvalue(dfw, stnode_data(st_arg1)); + } + else if (type1 == STTYPE_RANGE) { + reg1 = dfw_append_mk_range(dfw, st_arg1); + } + else { + g_assert_not_reached(); + } + + if (type2 == STTYPE_FIELD) { + hfinfo = stnode_data(st_arg2); + reg2 = dfw_append_read_tree(dfw, hfinfo->id); + + insn = dfvm_insn_new(IF_FALSE_GOTO); + jmp2 = dfvm_value_new(INSN_NUMBER); + insn->arg1 = jmp2; + dfw_append_insn(dfw, insn); + } + else if (type2 == STTYPE_FVALUE) { + reg2 = dfw_append_put_fvalue(dfw, stnode_data(st_arg2)); + } + else { + g_assert_not_reached(); + } + + insn = dfvm_insn_new(op); + val1 = dfvm_value_new(REGISTER); + val1->value.numeric = reg1; + val2 = dfvm_value_new(REGISTER); + val2->value.numeric = reg2; + insn->arg1 = val1; + insn->arg2 = val2; + dfw_append_insn(dfw, insn); + + if (jmp1) { + jmp1->value.numeric = dfw->next_insn_id; + } + + if (jmp2) { + jmp2->value.numeric = dfw->next_insn_id; + } +} + + +static void +gen_test(dfwork_t *dfw, stnode_t *st_node) +{ + test_op_t st_op; + stnode_t *st_arg1, *st_arg2; + dfvm_value_t *val1; + dfvm_insn_t *insn; + + header_field_info *hfinfo; + + sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2); + + switch (st_op) { + case TEST_OP_UNINITIALIZED: + g_assert_not_reached(); + break; + + case TEST_OP_EXISTS: + val1 = dfvm_value_new(FIELD_ID); + hfinfo = stnode_data(st_arg1); + val1->value.numeric = hfinfo->id; + insn = dfvm_insn_new(CHECK_EXISTS); + insn->arg1 = val1; + dfw_append_insn(dfw, insn); + break; + + case TEST_OP_NOT: + gencode(dfw, st_arg1); + insn = dfvm_insn_new(NOT); + dfw_append_insn(dfw, insn); + break; + + case TEST_OP_AND: + gencode(dfw, st_arg1); + + insn = dfvm_insn_new(IF_FALSE_GOTO); + val1 = dfvm_value_new(INSN_NUMBER); + insn->arg1 = val1; + dfw_append_insn(dfw, insn); + + gencode(dfw, st_arg2); + val1->value.numeric = dfw->next_insn_id; + break; + + case TEST_OP_OR: + gencode(dfw, st_arg1); + + insn = dfvm_insn_new(IF_TRUE_GOTO); + val1 = dfvm_value_new(INSN_NUMBER); + insn->arg1 = val1; + dfw_append_insn(dfw, insn); + + gencode(dfw, st_arg2); + val1->value.numeric = dfw->next_insn_id; + break; + + case TEST_OP_EQ: + gen_relation(dfw, ANY_EQ, st_arg1, st_arg2); + break; + + case TEST_OP_NE: + gen_relation(dfw, ANY_NE, st_arg1, st_arg2); + break; + + case TEST_OP_GT: + gen_relation(dfw, ANY_GT, st_arg1, st_arg2); + break; + + case TEST_OP_GE: + gen_relation(dfw, ANY_GE, st_arg1, st_arg2); + break; + + case TEST_OP_LT: + gen_relation(dfw, ANY_LT, st_arg1, st_arg2); + break; + + case TEST_OP_LE: + gen_relation(dfw, ANY_LE, st_arg1, st_arg2); + break; + } +} + +static void +gencode(dfwork_t *dfw, stnode_t *st_node) +{ + const char *name; + + name = stnode_type_name(st_node); + + switch (stnode_type_id(st_node)) { + case STTYPE_TEST: + gen_test(dfw, st_node); + break; + default: + g_assert_not_reached(); + } +} + + +void +dfw_gencode(dfwork_t *dfw) +{ + dfw->insns = g_ptr_array_new(); + dfw->loaded_fields = g_hash_table_new(g_direct_hash, g_direct_equal); + gencode(dfw, dfw->st_root); + dfw_append_insn(dfw, dfvm_insn_new(RETURN)); +} + |