diff options
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dfilter/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/dfilter/dfilter-int.h | 20 | ||||
-rw-r--r-- | epan/dfilter/dfilter.c | 20 | ||||
-rw-r--r-- | epan/dfilter/dfunctions.c | 156 | ||||
-rw-r--r-- | epan/dfilter/dfunctions.h | 16 | ||||
-rw-r--r-- | epan/dfilter/dfvm.c | 62 | ||||
-rw-r--r-- | epan/dfilter/dfvm.h | 1 | ||||
-rw-r--r-- | epan/dfilter/gencode.c | 103 | ||||
-rw-r--r-- | epan/dfilter/semcheck.c | 107 | ||||
-rw-r--r-- | epan/dfilter/sttype-function.c | 27 | ||||
-rw-r--r-- | epan/dfilter/sttype-function.h | 4 | ||||
-rw-r--r-- | epan/dfilter/sttype-pointer.c | 15 | ||||
-rw-r--r-- | epan/dfilter/sttype-pointer.h | 20 | ||||
-rw-r--r-- | epan/dfilter/syntax-tree.c | 18 | ||||
-rw-r--r-- | epan/dfilter/syntax-tree.h | 4 |
15 files changed, 431 insertions, 143 deletions
diff --git a/epan/dfilter/CMakeLists.txt b/epan/dfilter/CMakeLists.txt index 95ec4418ad..a7f542ceb9 100644 --- a/epan/dfilter/CMakeLists.txt +++ b/epan/dfilter/CMakeLists.txt @@ -23,6 +23,7 @@ set(DFILTER_HEADER_FILES gencode.h semcheck.h sttype-function.h + sttype-pointer.h sttype-range.h sttype-set.h sttype-test.h diff --git a/epan/dfilter/dfilter-int.h b/epan/dfilter/dfilter-int.h index dc50f6a75a..4d89277d8c 100644 --- a/epan/dfilter/dfilter-int.h +++ b/epan/dfilter/dfilter-int.h @@ -80,7 +80,7 @@ dfilter_fail(dfwork_t *dfw, stloc_t *err_loc, WS_NORETURN void dfilter_fail_throw(dfwork_t *dfw, stloc_t *err_loc, - long code, const char *format, ...) G_GNUC_PRINTF(4, 5); + const char *format, ...) G_GNUC_PRINTF(3, 4); void dfw_set_error_location(dfwork_t *dfw, stloc_t *err_loc); @@ -97,6 +97,24 @@ DfilterTrace(FILE *TraceFILE, char *zTracePrompt); header_field_info * dfilter_resolve_unparsed(dfwork_t *dfw, const char *name); +gboolean +dfw_resolve_unparsed(dfwork_t *dfw, stnode_t *st); + +fvalue_t * +dfilter_fvalue_from_unparsed(dfwork_t *dfw, ftenum_t ftype, stnode_t *st, + gboolean allow_partial_value, header_field_info *hfinfo_value_string); + +WS_RETNONNULL fvalue_t* +dfilter_fvalue_from_literal(dfwork_t *dfw, ftenum_t ftype, stnode_t *st, + gboolean allow_partial_value, header_field_info *hfinfo_value_string); + +WS_RETNONNULL fvalue_t * +dfilter_fvalue_from_string(dfwork_t *dfw, ftenum_t ftype, stnode_t *st, + header_field_info *hfinfo_value_string); + +WS_RETNONNULL fvalue_t * +dfilter_fvalue_from_charconst(dfwork_t *dfw, ftenum_t ftype, stnode_t *st); + const char *tokenstr(int token); #endif diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c index 24198660d2..39adb1cedd 100644 --- a/epan/dfilter/dfilter.c +++ b/epan/dfilter/dfilter.c @@ -76,15 +76,14 @@ dfilter_fail(dfwork_t *dfw, stloc_t *loc, } void -dfilter_fail_throw(dfwork_t *dfw, stloc_t *loc, - long code, const char *format, ...) +dfilter_fail_throw(dfwork_t *dfw, stloc_t *loc, const char *format, ...) { va_list args; va_start(args, format); dfilter_vfail(dfw, loc, format, args); va_end(args); - THROW(code); + THROW(TypeError); } void @@ -122,6 +121,21 @@ dfilter_resolve_unparsed(dfwork_t *dfw, const char *name) return NULL; } +gboolean +dfw_resolve_unparsed(dfwork_t *dfw, stnode_t *st) +{ + if (stnode_type_id(st) != STTYPE_UNPARSED) + return FALSE; + + header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, stnode_data(st)); + if (hfinfo != NULL) { + stnode_replace(st, STTYPE_FIELD, hfinfo); + return TRUE; + } + stnode_replace(st, STTYPE_LITERAL, g_strdup(stnode_data(st))); + return FALSE; +} + /* Initialize the dfilter module */ void dfilter_init(void) diff --git a/epan/dfilter/dfunctions.c b/epan/dfilter/dfunctions.c index 8f05c8e477..66250d7cb5 100644 --- a/epan/dfilter/dfunctions.c +++ b/epan/dfilter/dfunctions.c @@ -12,6 +12,7 @@ #include "dfilter-int.h" #include "dfunctions.h" +#include "sttype-pointer.h" #include <string.h> @@ -20,18 +21,19 @@ #include <wsutil/ws_assert.h> #define FAIL(dfw, node, ...) \ - dfilter_fail_throw(dfw, stnode_location(node), TypeError, __VA_ARGS__) + dfilter_fail_throw(dfw, stnode_location(node), __VA_ARGS__) /* Convert an FT_STRING using a callback function */ static gboolean -string_walk(GSList* arg1list, GSList **retval, gchar(*conv_func)(gchar)) +string_walk(GSList **args, guint32 arg_count, GSList **retval, gchar(*conv_func)(gchar)) { GSList *arg1; fvalue_t *arg_fvalue; fvalue_t *new_ft_string; char *s, *c; - arg1 = arg1list; + ws_assert(arg_count == 1); + arg1 = args[0]; while (arg1) { arg_fvalue = (fvalue_t *)arg1->data; /* XXX - it would be nice to handle FT_TVBUFF, too */ @@ -54,27 +56,28 @@ string_walk(GSList* arg1list, GSList **retval, gchar(*conv_func)(gchar)) /* dfilter function: lower() */ static gboolean -df_func_lower(GSList* arg1list, GSList *arg2junk _U_, GSList **retval) +df_func_lower(GSList **args, guint32 arg_count, GSList **retval) { - return string_walk(arg1list, retval, g_ascii_tolower); + return string_walk(args, arg_count, retval, g_ascii_tolower); } /* dfilter function: upper() */ static gboolean -df_func_upper(GSList* arg1list, GSList *arg2junk _U_, GSList **retval) +df_func_upper(GSList **args, guint32 arg_count, GSList **retval) { - return string_walk(arg1list, retval, g_ascii_toupper); + return string_walk(args, arg_count, retval, g_ascii_toupper); } /* dfilter function: len() */ static gboolean -df_func_len(GSList* arg1list, GSList *arg2junk _U_, GSList **retval) +df_func_len(GSList **args, guint32 arg_count, GSList **retval) { GSList *arg1; fvalue_t *arg_fvalue; fvalue_t *ft_len; - arg1 = arg1list; + ws_assert(arg_count == 1); + arg1 = args[0]; while (arg1) { arg_fvalue = (fvalue_t *)arg1->data; ft_len = fvalue_new(FT_UINT32); @@ -88,12 +91,15 @@ df_func_len(GSList* arg1list, GSList *arg2junk _U_, GSList **retval) /* dfilter function: count() */ static gboolean -df_func_count(GSList* arg1list, GSList *arg2junk _U_, GSList **retval) +df_func_count(GSList **args, guint32 arg_count, GSList **retval) { + GSList *arg1; fvalue_t *ft_ret; guint32 num_items; - num_items = (guint32)g_slist_length(arg1list); + ws_assert(arg_count == 1); + arg1 = args[0]; + num_items = (guint32)g_slist_length(arg1); ft_ret = fvalue_new(FT_UINT32); fvalue_set_uinteger(ft_ret, num_items); @@ -104,13 +110,16 @@ df_func_count(GSList* arg1list, GSList *arg2junk _U_, GSList **retval) /* dfilter function: string() */ static gboolean -df_func_string(GSList* arg1list, GSList *arg2junk _U_, GSList **retval) +df_func_string(GSList **args, guint32 arg_count, GSList **retval) { - GSList *arg1 = arg1list; + GSList *arg1; fvalue_t *arg_fvalue; fvalue_t *new_ft_string; char *s; + ws_assert(arg_count == 1); + arg1 = args[0]; + while (arg1) { arg_fvalue = (fvalue_t *)arg1->data; switch (fvalue_type_ftenum(arg_fvalue)) @@ -167,15 +176,53 @@ df_func_string(GSList* arg1list, GSList *arg2junk _U_, GSList **retval) return TRUE; } +static gboolean +df_func_compare(GSList **args, guint32 arg_count, GSList **retval, + gboolean (*fv_cmp)(const fvalue_t *a, const fvalue_t *b)) +{ + fvalue_t *fv_ret = NULL; + GSList *l; + guint32 i; + + for (i = 0; i < arg_count; i++) { + for (l = args[i]; l != NULL; l = l->next) { + if (fv_ret == NULL || fv_cmp(l->data, fv_ret)) { + fv_ret = l->data; + } + } + } + + *retval = g_slist_append(NULL, fvalue_dup(fv_ret)); + + return TRUE; +} + +/* Find maximum value. */ +static gboolean +df_func_max(GSList **args, guint32 arg_count, GSList **retval) +{ + return df_func_compare(args, arg_count, retval, fvalue_gt); +} + +/* Find minimum value. */ +static gboolean +df_func_min(GSList **args, guint32 arg_count, GSList **retval) +{ + return df_func_compare(args, arg_count, retval, fvalue_lt); +} + /* For upper() and lower() checks that the parameter passed to * it is an FT_STRING */ static void ul_semcheck_is_field_string(dfwork_t *dfw, const char *func_name, - int param_num, stnode_t *st_node) + GSList *param_list, stloc_t *func_loc _U_) { header_field_info *hfinfo; - ws_assert(param_num == 0); + ws_assert(g_slist_length(param_list) == 1); + stnode_t *st_node = param_list->data; + + dfw_resolve_unparsed(dfw, st_node); if (stnode_type_id(st_node) == STTYPE_FIELD) { hfinfo = stnode_data(st_node); @@ -188,9 +235,12 @@ ul_semcheck_is_field_string(dfwork_t *dfw, const char *func_name, static void ul_semcheck_is_field(dfwork_t *dfw, const char *func_name, - int param_num, stnode_t *st_node) + GSList *param_list, stloc_t *func_loc _U_) { - ws_assert(param_num == 0); + ws_assert(g_slist_length(param_list) == 1); + stnode_t *st_node = param_list->data; + + dfw_resolve_unparsed(dfw, st_node); if (stnode_type_id(st_node) == STTYPE_FIELD) return; @@ -200,11 +250,14 @@ ul_semcheck_is_field(dfwork_t *dfw, const char *func_name, static void ul_semcheck_string_param(dfwork_t *dfw, const char *func_name, - int param_num, stnode_t *st_node) + GSList *param_list, stloc_t *func_loc _U_) { header_field_info *hfinfo; - ws_assert(param_num == 0); + ws_assert(g_slist_length(param_list) == 1); + stnode_t *st_node = param_list->data; + + dfw_resolve_unparsed(dfw, st_node); if (stnode_type_id(st_node) == STTYPE_FIELD) { hfinfo = stnode_data(st_node); @@ -250,6 +303,69 @@ ul_semcheck_string_param(dfwork_t *dfw, const char *func_name, FAIL(dfw, st_node, "Only fields can be used as parameter for %s()", func_name); } +/* Check arguments are all the same type and they can be compared. */ +static void +ul_semcheck_compare(dfwork_t *dfw, const char *func_name, + GSList *param_list, stloc_t *func_loc) +{ + stnode_t *arg; + ftenum_t ftype, ft_arg; + GSList *l; + const header_field_info *hfinfo; + fvalue_t *fv; + + /* First argument must be a field not FT_NONE. */ + arg = param_list->data; + dfw_resolve_unparsed(dfw, arg); + ftype = sttype_pointer_ftenum(arg); + if (ftype == FT_NONE) { + FAIL(dfw, arg, "First argument to %s() must be a field, not %s", + func_name, stnode_type_name(arg)); + } + + for (l = param_list; l != NULL; l = l->next) { + arg = l->data; + dfw_resolve_unparsed(dfw, arg); + + switch (stnode_type_id(arg)) { + case STTYPE_FIELD: + case STTYPE_REFERENCE: + hfinfo = stnode_data(arg); + ft_arg = hfinfo->type; + break; + case STTYPE_LITERAL: + fv = dfilter_fvalue_from_literal(dfw, ftype, arg, FALSE, NULL); + stnode_replace(arg, STTYPE_FVALUE, fv); + ft_arg = fvalue_type_ftenum(stnode_data(arg)); + break; + case STTYPE_FVALUE: + ft_arg = fvalue_type_ftenum(stnode_data(arg)); + break; + default: + FAIL(dfw, arg, "Type %s is not valid for %s", + stnode_type_name(arg), func_name); + } + if (ft_arg == FT_NONE) { + dfilter_fail_throw(dfw, func_loc, + "Argument '%s' (FT_NONE) is not valid for %s()", + stnode_todisplay(arg), func_name); + } + if (ftype == FT_NONE) { + ftype = ft_arg; + } + if (ft_arg != ftype) { + dfilter_fail_throw(dfw, func_loc, + "Arguments to '%s' must have the same type", + func_name); + } + if (!ftype_can_cmp(ft_arg)) { + dfilter_fail_throw(dfw, func_loc, + "Argument '%s' to '%s' cannot be ordered", + stnode_todisplay(arg), func_name); + } + } +} + /* The table of all display-filter functions */ static df_func_def_t df_functions[] = { @@ -258,6 +374,8 @@ df_functions[] = { { "len", df_func_len, FT_UINT32, 1, 1, ul_semcheck_is_field }, { "count", df_func_count, FT_UINT32, 1, 1, ul_semcheck_is_field }, { "string", df_func_string, FT_STRING, 1, 1, ul_semcheck_string_param }, + { "max", df_func_max, /*Any*/ 0, 1, 0, ul_semcheck_compare }, + { "min", df_func_min, /*Any*/ 0, 1, 0, ul_semcheck_compare }, { NULL, NULL, FT_NONE, 0, 0, NULL } }; diff --git a/epan/dfilter/dfunctions.h b/epan/dfilter/dfunctions.h index d9f1de1daa..60cae3a33e 100644 --- a/epan/dfilter/dfunctions.h +++ b/epan/dfilter/dfunctions.h @@ -14,27 +14,23 @@ #include <ftypes/ftypes.h> #include "syntax-tree.h" +/* Functions take any number of arguments and return 1. */ + /* The run-time logic of the dfilter function */ -typedef gboolean (*DFFuncType)(GSList *arg1list, GSList *arg2list, GSList **retval); +typedef gboolean (*DFFuncType)(GSList **arg_list, guint32 arg_count, GSList **retval); /* The semantic check for the dfilter function */ typedef void (*DFSemCheckType)(dfwork_t *dfw, const char *func_name, - int param_num, stnode_t *st_node); - -/* If a function needs more args than this, increase - * this macro and add more arg members to the dfvm_insn_t - * struct in dfvm.h, and add some logic to dfw_append_function() - * and dfvm_apply() */ -#define DFUNCTION_MAX_NARGS 2 + GSList *param_list, stloc_t *func_loc); /* This is a "function definition" record, holding everything * we need to know about a function */ typedef struct { const char *name; DFFuncType function; - ftenum_t retval_ftype; + ftenum_t retval_ftype; /* 0 means return value is the same as input argument(s) */ guint min_nargs; - guint max_nargs; + guint max_nargs; /* 0 for no limit */ DFSemCheckType semcheck_param_function; } df_func_def_t; diff --git a/epan/dfilter/dfvm.c b/epan/dfilter/dfvm.c index 0afe51e48b..eaaa1f4828 100644 --- a/epan/dfilter/dfvm.c +++ b/epan/dfilter/dfvm.c @@ -14,6 +14,9 @@ #include <ftypes/ftypes.h> #include <wsutil/ws_assert.h> +static void +debug_register(GSList *reg, guint32 num); + dfvm_insn_t* dfvm_insn_new(dfvm_opcode_t op) { @@ -170,11 +173,14 @@ dfvm_value_tostr(dfvm_value_t *v) s = ws_strdup(ws_regex_pattern(v->value.pcre)); break; case REGISTER: - s = ws_strdup_printf("reg#%u", v->value.numeric); + s = ws_strdup_printf("reg#%"G_GUINT32_FORMAT, v->value.numeric); break; case FUNCTION_DEF: s = ws_strdup(v->value.funcdef->name); break; + case INTEGER: + s = ws_strdup_printf("%"G_GUINT32_FORMAT, v->value.numeric); + break; default: s = ws_strdup("FIXME"); } @@ -226,14 +232,20 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references) id, arg1_str, arg2_str); break; + case PUT_FVALUE: + wmem_strbuf_append_printf(buf, "%05d PUT_FVALUE\t%s -> %s\n", + id, arg1_str, arg2_str); + break; + case CALL_FUNCTION: wmem_strbuf_append_printf(buf, "%05d CALL_FUNCTION\t%s(", id, arg1_str); if (arg3_str) { wmem_strbuf_append_printf(buf, "%s", arg3_str); } - if (arg4_str) { - wmem_strbuf_append_printf(buf, ", %s", arg4_str); + for (guint32 i = 1; i <= arg4->value.numeric; i++) { + wmem_strbuf_append_printf(buf, ", reg#%"G_GUINT32_FORMAT, + arg3->value.numeric + i); } wmem_strbuf_append_printf(buf, ") -> %s\n", arg2_str); break; @@ -697,28 +709,32 @@ mk_range(dfilter_t *df, dfvm_value_t *from_arg, dfvm_value_t *to_arg, df->free_registers[to_arg->value.numeric] = (GDestroyNotify)fvalue_free; } +/* + * arg1: function def + * arg2: return register + * arg3: first input register + * arg4: number of input registers after first + */ static gboolean call_function(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2, dfvm_value_t *arg3, dfvm_value_t *arg4) { df_func_def_t *funcdef; - GSList *param1 = NULL; - GSList *param2 = NULL; GSList *retval = NULL; gboolean accum; + guint32 reg_return, reg_first_arg, more_args_count; funcdef = arg1->value.funcdef; - if (arg3) { - param1 = df->registers[arg3->value.numeric]; - } - if (arg4) { - param2 = df->registers[arg4->value.numeric]; - } - accum = funcdef->function(param1, param2, &retval); + reg_return = arg2->value.numeric; + reg_first_arg = arg3->value.numeric; + more_args_count = arg4->value.numeric; + + accum = funcdef->function(&df->registers[reg_first_arg], 1 + more_args_count, &retval); - df->registers[arg2->value.numeric] = retval; + /* Write return registers. */ + df->registers[reg_return] = retval; // functions create a new value, so own it. - df->free_registers[arg2->value.numeric] = (GDestroyNotify)fvalue_free; + df->free_registers[reg_return] = (GDestroyNotify)fvalue_free; return accum; } @@ -731,6 +747,8 @@ static void debug_op_error(fvalue_t *v1, fvalue_t *v2, const char *op, const cha g_free(s2); } +/* Used for temporary debugging only, don't leave in production code (at + * a minimum WS_DEBUG_HERE must be replaced by another log level). */ static void _U_ debug_register(GSList *reg, guint32 num) { @@ -748,7 +766,7 @@ debug_register(GSList *reg, guint32 num) wmem_strbuf_append_c(buf, ' '); } wmem_strbuf_append_c(buf, '}'); - ws_noisy("%s", wmem_strbuf_get_str(buf)); + WS_DEBUG_HERE("%s", wmem_strbuf_get_str(buf)); wmem_strbuf_destroy(buf); } @@ -865,6 +883,16 @@ mk_minus(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *to_arg) df->free_registers[to_arg->value.numeric] = (GDestroyNotify)fvalue_free; } +static void +put_fvalue(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *to_arg) +{ + fvalue_t *fv = arg1->value.fvalue; + df->registers[to_arg->value.numeric] = g_slist_append(NULL, fv); + + /* Memory is owned by the dfvm_value_t. */ + df->free_registers[to_arg->value.numeric] = NULL; +} + gboolean dfvm_apply(dfilter_t *df, proto_tree *tree) { @@ -913,6 +941,10 @@ dfvm_apply(dfilter_t *df, proto_tree *tree) accum = read_reference(df, arg1, arg2); break; + case PUT_FVALUE: + put_fvalue(df, arg1, arg2); + break; + case CALL_FUNCTION: accum = call_function(df, arg1, arg2, arg3, arg4); break; diff --git a/epan/dfilter/dfvm.h b/epan/dfilter/dfvm.h index fc6902218f..565e5568fd 100644 --- a/epan/dfilter/dfvm.h +++ b/epan/dfilter/dfvm.h @@ -54,6 +54,7 @@ typedef enum { RETURN, READ_TREE, READ_REFERENCE, + PUT_FVALUE, ALL_EQ, ANY_EQ, ALL_NE, diff --git a/epan/dfilter/gencode.c b/epan/dfilter/gencode.c index d68ef697e2..eb90b6cbc3 100644 --- a/epan/dfilter/gencode.c +++ b/epan/dfilter/gencode.c @@ -38,12 +38,13 @@ dfw_append_insn(dfwork_t *dfw, dfvm_insn_t *insn) /* returns register number */ static dfvm_value_t * -dfw_append_read_tree(dfwork_t *dfw, header_field_info *hfinfo) +dfw_append_read_tree(dfwork_t *dfw, header_field_info *hfinfo, gboolean reuse_register) { dfvm_insn_t *insn; int reg = -1; dfvm_value_t *reg_val, *val1; gboolean added_new_hfinfo = FALSE; + void *loaded_key; /* Rewind to find the first field of this name. */ while (hfinfo->same_name_prev_id != -1) { @@ -53,14 +54,21 @@ dfw_append_read_tree(dfwork_t *dfw, header_field_info *hfinfo) /* Keep track of which registers * were used for which hfinfo's so that we * can re-use registers. */ - reg = GPOINTER_TO_INT( - g_hash_table_lookup(dfw->loaded_fields, hfinfo)); - if (reg) { - /* Reg's are stored in has as reg+1, so - * that the non-existence of a hfinfo in - * the hash, or 0, can be differentiated from - * a hfinfo being loaded into register #0. */ - reg--; + loaded_key = g_hash_table_lookup(dfw->loaded_fields, hfinfo); + if (loaded_key != NULL) { + /* Already loaded at least once. */ + if (reuse_register) { + /* + * Reg's are stored in has as reg+1, so + * that the non-existence of a hfinfo in + * the hash, or 0, can be differentiated from + * a hfinfo being loaded into register #0. + */ + reg = GPOINTER_TO_INT(loaded_key) - 1; + } + else { + reg = dfw->next_register++; + } } else { reg = dfw->next_register++; @@ -160,6 +168,23 @@ dfw_append_mk_range(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr) return reg_val; } +/* returns register number */ +static dfvm_value_t * +dfw_append_put_fvalue(dfwork_t *dfw, fvalue_t *fv) +{ + dfvm_insn_t *insn; + dfvm_value_t *reg_val, *val1; + + insn = dfvm_insn_new(PUT_FVALUE); + val1 = dfvm_value_new_fvalue(fv); + insn->arg1 = dfvm_value_ref(val1); + reg_val = dfvm_value_new_register(dfw->next_register++); + insn->arg2 = dfvm_value_ref(reg_val); + dfw_append_insn(dfw, insn); + + return reg_val; +} + /* returns register number that the functions's result will be in. */ static dfvm_value_t * dfw_append_function(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr) @@ -167,8 +192,10 @@ dfw_append_function(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr) GSList *params; GSList *param_jumps = NULL; dfvm_value_t *jmp; - dfvm_insn_t *insn; - dfvm_value_t *reg_val, *val1, *val3, *val4; + dfvm_insn_t *insn, *insn_jump; + dfvm_value_t *reg_val, *val1, *val3, *val4, *val_arg; + guint32 reg_first, more_args_count; + stnode_t *arg; /* Create the new DFVM instruction */ insn = dfvm_insn_new(CALL_FUNCTION); @@ -176,26 +203,56 @@ dfw_append_function(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr) insn->arg1 = dfvm_value_ref(val1); reg_val = dfvm_value_new_register(dfw->next_register++); insn->arg2 = dfvm_value_ref(reg_val); - insn->arg3 = NULL; - insn->arg4 = NULL; + /* Create input arguments */ params = sttype_function_params(node); - if (params) { - val3 = gen_entity(dfw, params->data, ¶m_jumps); - insn->arg3 = dfvm_value_ref(val3); + ws_assert(params); + val3 = dfw_append_read_tree(dfw, stnode_steal_data(params->data), FALSE); + insn->arg3 = dfvm_value_ref(val3); + /* Add a jump if reading argument failed. */ + insn_jump = dfvm_insn_new(IF_FALSE_GOTO); + jmp = dfvm_value_new(INSN_NUMBER); + insn_jump->arg1 = dfvm_value_ref(jmp); + dfw_append_insn(dfw, insn_jump); + param_jumps = g_slist_prepend(param_jumps, jmp); + + params = params->next; + reg_first = val3->value.numeric; + more_args_count = 0; + while (params) { + arg = params->data; + switch (stnode_type_id(arg)) { + case STTYPE_FVALUE: + dfw_append_put_fvalue(dfw, stnode_steal_data(arg)); + break; + case STTYPE_FIELD: + /* We cannot reuse registers here because the function calling + * convention is to pass input arguments sequentially. */ + val_arg = dfw_append_read_tree(dfw, stnode_data(arg), FALSE); + /* Assert the registers are numbered sequentially. */ + ws_assert(val_arg->value.numeric == reg_first + more_args_count + 1); + /* Add a jump if reading argument failed. */ + insn_jump = dfvm_insn_new(IF_FALSE_GOTO); + jmp = dfvm_value_new(INSN_NUMBER); + insn_jump->arg1 = dfvm_value_ref(jmp); + dfw_append_insn(dfw, insn_jump); + param_jumps = g_slist_prepend(param_jumps, jmp); + break; + default: + ws_assert_not_reached(); + } + more_args_count++; params = params->next; } - if (params) { - val4 = gen_entity(dfw, params->data, ¶m_jumps); - insn->arg4 = dfvm_value_ref(val4); - } - ws_assert(!g_slist_next(params)); + val4 = dfvm_value_new(INTEGER); + val4->value.numeric = more_args_count; + insn->arg4 = dfvm_value_ref(val4); dfw_append_insn(dfw, insn); /* If any of our parameters failed, send them to * our own failure instruction. This *has* to be done - * after we caled dfw_append_insn above so that + * after we called dfw_append_insn above so that * we know what the next DFVM insruction is, via * dfw->next_insn_id */ g_slist_foreach(param_jumps, fixup_jumps, dfw); @@ -390,7 +447,7 @@ gen_entity(dfwork_t *dfw, stnode_t *st_arg, GSList **jumps_ptr) if (e_type == STTYPE_FIELD) { hfinfo = stnode_data(st_arg); - val = dfw_append_read_tree(dfw, hfinfo); + val = dfw_append_read_tree(dfw, hfinfo, TRUE); insn = dfvm_insn_new(IF_FALSE_GOTO); jmp = dfvm_value_new(INSN_NUMBER); diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c index 7a4eb5452b..838d2d847c 100644 --- a/epan/dfilter/semcheck.c +++ b/epan/dfilter/semcheck.c @@ -32,8 +32,7 @@ #define FAIL(dfw, node, ...) \ do { \ ws_noisy("Semantic check failed here."); \ - dfilter_fail_throw(dfw, stnode_location(node), \ - TypeError, __VA_ARGS__); \ + dfilter_fail_throw(dfw, stnode_location(node), __VA_ARGS__); \ } while (0) static void @@ -160,7 +159,7 @@ node_is_constant(stnode_t *node) /* Gets an fvalue from a string, and sets the error message on failure. */ WS_RETNONNULL -static fvalue_t* +fvalue_t* dfilter_fvalue_from_literal(dfwork_t *dfw, ftenum_t ftype, stnode_t *st, gboolean allow_partial_value, header_field_info *hfinfo_value_string) { @@ -190,7 +189,7 @@ dfilter_fvalue_from_literal(dfwork_t *dfw, ftenum_t ftype, stnode_t *st, return fv; } -static fvalue_t * +fvalue_t * dfilter_fvalue_from_unparsed(dfwork_t *dfw, ftenum_t ftype, stnode_t *st, gboolean allow_partial_value, header_field_info *hfinfo_value_string) { @@ -243,7 +242,7 @@ dfilter_fvalue_from_unparsed(dfwork_t *dfw, ftenum_t ftype, stnode_t *st, /* Gets an fvalue from a string, and sets the error message on failure. */ WS_RETNONNULL -static fvalue_t * +fvalue_t * dfilter_fvalue_from_string(dfwork_t *dfw, ftenum_t ftype, stnode_t *st, header_field_info *hfinfo_value_string) { @@ -271,21 +270,6 @@ dfilter_fvalue_from_string(dfwork_t *dfw, ftenum_t ftype, stnode_t *st, return fv; } -static gboolean -resolve_unparsed(dfwork_t *dfw, stnode_t *st) -{ - if (stnode_type_id(st) != STTYPE_UNPARSED) - return FALSE; - - header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, stnode_data(st)); - if (hfinfo != NULL) { - stnode_replace(st, STTYPE_FIELD, hfinfo); - return TRUE; - } - stnode_replace(st, STTYPE_LITERAL, g_strdup(stnode_data(st))); - return FALSE; -} - /* Creates a FT_UINT32 fvalue with a given value. */ static fvalue_t* mk_uint32_fvalue(guint32 val) @@ -524,7 +508,7 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1) { LOG_NODE(st_arg1); - resolve_unparsed(dfw, st_arg1); + dfw_resolve_unparsed(dfw, st_arg1); switch (stnode_type_id(st_arg1)) { case STTYPE_FIELD: @@ -578,7 +562,7 @@ check_drange_sanity(dfwork_t *dfw, stnode_t *st) entity1 = sttype_range_entity(st); ws_assert(entity1); - resolve_unparsed(dfw, entity1); + dfw_resolve_unparsed(dfw, entity1); if (stnode_type_id(entity1) == STTYPE_FIELD) { hfinfo1 = stnode_data(entity1); @@ -589,15 +573,13 @@ check_drange_sanity(dfwork_t *dfw, stnode_t *st) hfinfo1->abbrev, ftype_pretty_name(ftype1)); } } else if (stnode_type_id(entity1) == STTYPE_FUNCTION) { - df_func_def_t *funcdef = sttype_function_funcdef(entity1); - ftype1 = funcdef->retval_ftype; + check_function(dfw, entity1); + ftype1 = sttype_function_retval_ftype(entity1); if (!ftype_can_slice(ftype1)) { FAIL(dfw, entity1, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.", - funcdef->name, ftype_pretty_name(ftype1)); + sttype_function_name(entity1), ftype_pretty_name(ftype1)); } - - check_function(dfw, entity1); } else if (stnode_type_id(entity1) == STTYPE_RANGE) { /* Should this be rejected instead? */ check_drange_sanity(dfw, entity1); @@ -627,7 +609,6 @@ check_function(dfwork_t *dfw, stnode_t *st_node) { df_func_def_t *funcdef; GSList *params; - guint iparam; guint nparams; LOG_NODE(st_node); @@ -639,22 +620,17 @@ check_function(dfwork_t *dfw, stnode_t *st_node) if (nparams < funcdef->min_nargs) { FAIL(dfw, st_node, "Function %s needs at least %u arguments.", funcdef->name, funcdef->min_nargs); - } else if (nparams > funcdef->max_nargs) { + } else if (funcdef->max_nargs > 0 && nparams > funcdef->max_nargs) { FAIL(dfw, st_node, "Function %s can only accept %u arguments.", funcdef->name, funcdef->max_nargs); } - iparam = 0; - while (params) { - resolve_unparsed(dfw, params->data); - funcdef->semcheck_param_function(dfw, funcdef->name, iparam, params->data); - params = params->next; - iparam++; - } + funcdef->semcheck_param_function(dfw, funcdef->name, params, + stnode_location(st_node)); } WS_RETNONNULL -static fvalue_t * +fvalue_t * dfilter_fvalue_from_charconst(dfwork_t *dfw, ftenum_t ftype, stnode_t *st) { fvalue_t *fvalue; @@ -681,7 +657,6 @@ check_relation_LHS_FIELD(dfwork_t *dfw, test_op_t st_op, { sttype_id_t type2; header_field_info *hfinfo1, *hfinfo2; - df_func_def_t *funcdef; ftenum_t ftype1, ftype2; fvalue_t *fvalue; @@ -756,21 +731,19 @@ again: } } else if (type2 == STTYPE_FUNCTION) { - funcdef = sttype_function_funcdef(st_arg2); - ftype2 = funcdef->retval_ftype; + check_function(dfw, st_arg2); + ftype2 = sttype_function_retval_ftype(st_arg2); if (!compatible_ftypes(ftype1, ftype2)) { FAIL(dfw, st_arg2, "%s (type=%s) and return value of %s() (type=%s) are not of compatible types.", hfinfo1->abbrev, ftype_pretty_name(ftype1), - funcdef->name, ftype_pretty_name(ftype2)); + sttype_function_name(st_arg2), ftype_pretty_name(ftype2)); } if (!can_func(ftype2)) { FAIL(dfw, st_arg2, "return value of %s() (type=%s) cannot participate in specified comparison.", - funcdef->name, ftype_pretty_name(ftype2)); + sttype_function_name(st_arg2), ftype_pretty_name(ftype2)); } - - check_function(dfw, st_arg2); } else if (type2 == STTYPE_PCRE) { ws_assert(st_op == TEST_OP_MATCHES); @@ -851,21 +824,19 @@ again: check_drange_sanity(dfw, st_arg2); } else if (type2 == STTYPE_FUNCTION) { - df_func_def_t *funcdef = sttype_function_funcdef(st_arg2); - ftype2 = funcdef->retval_ftype; + check_function(dfw, st_arg2); + ftype2 = sttype_function_retval_ftype(st_arg2); if (!is_bytes_type(ftype2)) { if (!ftype_can_slice(ftype2)) { FAIL(dfw, st_arg2, "Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.", - funcdef->name, + sttype_function_name(st_arg2), ftype_pretty_name(ftype2)); } /* Convert function result to bytes */ convert_to_bytes(st_arg2); } - - check_function(dfw, st_arg2); } else if (type2 == STTYPE_PCRE) { ws_assert(st_op == TEST_OP_MATCHES); @@ -900,19 +871,15 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, test_op_t st_op, header_field_info *hfinfo2; ftenum_t ftype1, ftype2; fvalue_t *fvalue; - df_func_def_t *funcdef; - df_func_def_t *funcdef2; - /* GSList *params; */ LOG_NODE(st_node); check_function(dfw, st_arg1); - funcdef = sttype_function_funcdef(st_arg1); - ftype1 = funcdef->retval_ftype; + ftype1 = sttype_function_retval_ftype(st_arg1); if (!can_func(ftype1)) { FAIL(dfw, st_arg1, "Function %s (type=%s) cannot participate in %s comparison.", - funcdef->name, ftype_pretty_name(ftype1), + sttype_function_name(st_arg1), ftype_pretty_name(ftype1), stnode_todisplay(st_node)); } @@ -925,7 +892,7 @@ again: if (!compatible_ftypes(ftype1, ftype2)) { FAIL(dfw, st_arg2, "Function %s and %s are not of compatible types.", - funcdef->name, hfinfo2->abbrev); + sttype_function_name(st_arg2), hfinfo2->abbrev); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ @@ -959,7 +926,7 @@ again: if (!is_bytes_type(ftype1)) { if (!ftype_can_slice(ftype1)) { FAIL(dfw, st_arg1, "Function \"%s\" is a %s and cannot be converted into a sequence of bytes.", - funcdef->name, + sttype_function_name(st_arg1), ftype_pretty_name(ftype1)); } @@ -968,22 +935,20 @@ again: } } else if (type2 == STTYPE_FUNCTION) { - funcdef2 = sttype_function_funcdef(st_arg2); - ftype2 = funcdef2->retval_ftype; + check_function(dfw, st_arg2); + ftype2 = sttype_function_retval_ftype(st_arg2); if (!compatible_ftypes(ftype1, ftype2)) { FAIL(dfw, st_arg2, "Return values of function %s (type=%s) and function %s (type=%s) are not of compatible types.", - funcdef->name, ftype_pretty_name(ftype1), funcdef2->name, ftype_pretty_name(ftype2)); + sttype_function_name(st_arg1), ftype_pretty_name(ftype1), sttype_function_name(st_arg1), ftype_pretty_name(ftype2)); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { FAIL(dfw, st_arg2, "Return value of %s (type=%s) cannot participate in specified comparison.", - funcdef2->name, ftype_pretty_name(ftype2)); + sttype_function_name(st_arg2), ftype_pretty_name(ftype2)); } - - check_function(dfw, st_arg2); } else if (type2 == STTYPE_PCRE) { ws_assert(st_op == TEST_OP_MATCHES); @@ -1046,7 +1011,7 @@ check_relation(dfwork_t *dfw, test_op_t st_op, { LOG_NODE(st_node); - resolve_unparsed(dfw, st_arg1); + dfw_resolve_unparsed(dfw, st_arg1); switch (stnode_type_id(st_arg1)) { case STTYPE_FIELD: @@ -1078,7 +1043,7 @@ check_relation_contains(dfwork_t *dfw, stnode_t *st_node, { LOG_NODE(st_node); - resolve_unparsed(dfw, st_arg1); + dfw_resolve_unparsed(dfw, st_arg1); switch (stnode_type_id(st_arg1)) { case STTYPE_FIELD: @@ -1111,7 +1076,7 @@ check_relation_matches(dfwork_t *dfw, stnode_t *st_node, LOG_NODE(st_node); - resolve_unparsed(dfw, st_arg1); + dfw_resolve_unparsed(dfw, st_arg1); if (stnode_type_id(st_arg2) != STTYPE_STRING) { FAIL(dfw, st_arg2, "Matches requires a double quoted string on the right side."); @@ -1158,7 +1123,7 @@ check_relation_in(dfwork_t *dfw, stnode_t *st_node _U_, LOG_NODE(st_node); - resolve_unparsed(dfw, st_arg1); + dfw_resolve_unparsed(dfw, st_arg1); if (stnode_type_id(st_arg1) != STTYPE_FIELD) { FAIL(dfw, st_arg1, "Only a field may be tested for membership in a set."); @@ -1261,7 +1226,7 @@ check_arithmetic_entity(dfwork_t *dfw, stnode_t *st_arg, ftenum_t lhs_ftype) * is none we must have been passed an entity with a definite type * (field, function, etc). */ - resolve_unparsed(dfw, st_arg); + dfw_resolve_unparsed(dfw, st_arg); type = stnode_type_id(st_arg); if (type == STTYPE_LITERAL) { @@ -1277,9 +1242,7 @@ check_arithmetic_entity(dfwork_t *dfw, stnode_t *st_arg, ftenum_t lhs_ftype) } else if (type == STTYPE_FUNCTION) { check_function(dfw, st_arg); - - df_func_def_t *funcdef = sttype_function_funcdef(st_arg); - ftype = funcdef->retval_ftype; + ftype = sttype_function_retval_ftype(st_arg); } else if (type == STTYPE_RANGE) { check_drange_sanity(dfw, st_arg); @@ -1312,7 +1275,7 @@ check_arithmetic_expr(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype) } sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2); - resolve_unparsed(dfw, st_arg1); + dfw_resolve_unparsed(dfw, st_arg1); /* On the LHS we require a field-like value as the first term. */ if (lhs_ftype == FT_NONE && node_is_constant(st_arg1)) { diff --git a/epan/dfilter/sttype-function.c b/epan/dfilter/sttype-function.c index e4036a30cd..bc1c6021f2 100644 --- a/epan/dfilter/sttype-function.c +++ b/epan/dfilter/sttype-function.c @@ -119,6 +119,33 @@ sttype_function_funcdef(stnode_t *node) return stfuncrec->funcdef; } +ftenum_t +sttype_function_retval_ftype(stnode_t *node) +{ + function_t *stfuncrec; + + stfuncrec = stnode_data(node); + ws_assert_magic(stfuncrec, FUNCTION_MAGIC); + if (stfuncrec->funcdef->retval_ftype != 0) + return stfuncrec->funcdef->retval_ftype; + + if (stfuncrec->params) { + stnode_t *first_arg = stfuncrec->params->data; + return stnode_ftenum(first_arg); + } + return FT_NONE; +} + +const char * +sttype_function_name(stnode_t *node) +{ + function_t *stfuncrec; + + stfuncrec = stnode_data(node); + ws_assert_magic(stfuncrec, FUNCTION_MAGIC); + return stfuncrec->funcdef->name; +} + /* Get the parameters for a function stnode_t. */ GSList* sttype_function_params(stnode_t *node) diff --git a/epan/dfilter/sttype-function.h b/epan/dfilter/sttype-function.h index 68b9c57d4d..48294ce2d7 100644 --- a/epan/dfilter/sttype-function.h +++ b/epan/dfilter/sttype-function.h @@ -21,6 +21,10 @@ sttype_function_set_params(stnode_t *node, GSList *params); /* Get the function-definition record for a function stnode_t. */ df_func_def_t* sttype_function_funcdef(stnode_t *node); +ftenum_t sttype_function_retval_ftype(stnode_t *node); + +const char *sttype_function_name(stnode_t *node); + /* Get the parameters for a function stnode_t. */ GSList* sttype_function_params(stnode_t *node); diff --git a/epan/dfilter/sttype-pointer.c b/epan/dfilter/sttype-pointer.c index b61a82b048..e91634ad3b 100644 --- a/epan/dfilter/sttype-pointer.c +++ b/epan/dfilter/sttype-pointer.c @@ -8,6 +8,7 @@ */ #include "config.h" +#include "sttype-pointer.h" #include "ftypes/ftypes.h" #include "syntax-tree.h" @@ -109,6 +110,20 @@ range_node_tostr(const void *data, gboolean pretty _U_) return drange_node_tostr(data); } +ftenum_t +sttype_pointer_ftenum(stnode_t *node) +{ + switch (node->type->id) { + case STTYPE_FIELD: + return ((header_field_info *)node->data)->type; + case STTYPE_FVALUE: + return fvalue_type_ftenum(node->data); + default: + break; + } + return FT_NONE; +} + void sttype_register_pointer(void) { diff --git a/epan/dfilter/sttype-pointer.h b/epan/dfilter/sttype-pointer.h new file mode 100644 index 0000000000..54aa28edec --- /dev/null +++ b/epan/dfilter/sttype-pointer.h @@ -0,0 +1,20 @@ +/** @file + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 2001 Gerald Combs + * + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef STTYPE_POINTER_H +#define STTYPE_POINTER_H + +#include "dfilter-int.h" +#include <epan/ftypes/ftypes.h> + +ftenum_t +sttype_pointer_ftenum(stnode_t *node); + +#endif diff --git a/epan/dfilter/syntax-tree.c b/epan/dfilter/syntax-tree.c index 1ea5527349..bd72a74222 100644 --- a/epan/dfilter/syntax-tree.c +++ b/epan/dfilter/syntax-tree.c @@ -15,6 +15,8 @@ #include <wsutil/str_util.h> #include <wsutil/glib-compat.h> #include "sttype-test.h" +#include "sttype-pointer.h" +#include "sttype-function.h" #include "dfilter-int.h" /* Keep track of sttype_t's via their sttype_id_t number */ @@ -211,6 +213,22 @@ stnode_type_id(stnode_t *node) return STTYPE_UNINITIALIZED; } +ftenum_t +stnode_ftenum(stnode_t *node) +{ + ws_assert_magic(node, STNODE_MAGIC); + switch (node->type->id) { + case STTYPE_FVALUE: + case STTYPE_FIELD: + return sttype_pointer_ftenum(node); + case STTYPE_FUNCTION: + return sttype_function_retval_ftype(node); + default: + break; + } + return FT_NONE; +} + gpointer stnode_data(stnode_t *node) { diff --git a/epan/dfilter/syntax-tree.h b/epan/dfilter/syntax-tree.h index c1ee49769f..796c70d349 100644 --- a/epan/dfilter/syntax-tree.h +++ b/epan/dfilter/syntax-tree.h @@ -15,6 +15,7 @@ #include <wsutil/ws_assert.h> #include <wsutil/wslog.h> +#include <epan/ftypes/ftypes.h> /** @file */ @@ -137,6 +138,9 @@ stnode_type_name(stnode_t *node); sttype_id_t stnode_type_id(stnode_t *node); +ftenum_t +stnode_ftenum(stnode_t *node); + gpointer stnode_data(stnode_t *node); |