aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
authorJoão Valverde <j@v6e.pt>2022-04-16 02:42:20 +0100
committerJoão Valverde <j@v6e.pt>2022-04-18 17:10:31 +0100
commitfab32ea0cb5ccbce9327c861f4819b8a6e3980d9 (patch)
treea079ec80c18831281bf7cd1e6afb888bcbcdb9fc /epan
parent92c1519dfef8c42d3899e60beed226cd040a212e (diff)
dfilter: Allow arithmetic expressions as function arguments
This allows writing moderately complex expressions, for example a float epsilon test (#16483): Filter: {abs(_ws.ftypes.double - 1) / max(abs(_ws.ftypes.double), abs(1))} < 0.01 Syntax tree: 0 TEST_LT: 1 OP_DIVIDE: 2 FUNCTION(abs#1): 3 OP_SUBTRACT: 4 FIELD(_ws.ftypes.double) 4 FVALUE(1 <FT_DOUBLE>) 2 FUNCTION(max#2): 3 FUNCTION(abs#1): 4 FIELD(_ws.ftypes.double) 3 FUNCTION(abs#1): 4 FVALUE(1 <FT_DOUBLE>) 1 FVALUE(0.01 <FT_DOUBLE>) Instructions: 00000 READ_TREE _ws.ftypes.double -> reg#1 00001 IF_FALSE_GOTO 3 00002 SUBRACT reg#1 - 1 <FT_DOUBLE> -> reg#2 00003 STACK_PUSH reg#2 00004 CALL_FUNCTION abs(reg#2) -> reg#0 00005 STACK_POP 1 00006 IF_FALSE_GOTO 24 00007 READ_TREE _ws.ftypes.double -> reg#1 00008 IF_FALSE_GOTO 9 00009 STACK_PUSH reg#1 00010 CALL_FUNCTION abs(reg#1) -> reg#4 00011 STACK_POP 1 00012 IF_FALSE_GOTO 13 00013 STACK_PUSH reg#4 00014 STACK_PUSH 1 <FT_DOUBLE> 00015 CALL_FUNCTION abs(1 <FT_DOUBLE>) -> reg#5 00016 STACK_POP 1 00017 IF_FALSE_GOTO 18 00018 STACK_PUSH reg#5 00019 CALL_FUNCTION max(reg#5, reg#4) -> reg#3 00020 STACK_POP 2 00021 IF_FALSE_GOTO 24 00022 DIVIDE reg#0 / reg#3 -> reg#6 00023 ANY_LT reg#6 < 0.01 <FT_DOUBLE> 00024 RETURN We now use a stack to pass arguments to the function. The stack is implemented as a list of lists (list of registers). Arguments may still be non-existent to functions (this is a feature). Functions must check for nil arguments (NULL lists) and handle that case. It's somewhat complicated to allow literal values and test compatibility for different types, both because of lack of type information with unparsed/literal and also because it is an underdeveloped area in the code. In my limited testing it was good enough and useful, further enhancements are left for future work.
Diffstat (limited to 'epan')
-rw-r--r--epan/dfilter/dfilter-int.h2
-rw-r--r--epan/dfilter/dfilter.c7
-rw-r--r--epan/dfilter/dfunctions.c184
-rw-r--r--epan/dfilter/dfunctions.h5
-rw-r--r--epan/dfilter/dfvm.c189
-rw-r--r--epan/dfilter/dfvm.h8
-rw-r--r--epan/dfilter/gencode.c128
-rw-r--r--epan/dfilter/grammar.lemon4
-rw-r--r--epan/dfilter/semcheck.c45
-rw-r--r--epan/dfilter/semcheck.h5
-rw-r--r--epan/dfilter/sttype-function.c37
-rw-r--r--epan/dfilter/sttype-function.h2
-rw-r--r--epan/dfilter/sttype-test.c24
-rw-r--r--epan/dfilter/syntax-tree.c30
-rw-r--r--epan/dfilter/syntax-tree.h3
15 files changed, 413 insertions, 260 deletions
diff --git a/epan/dfilter/dfilter-int.h b/epan/dfilter/dfilter-int.h
index 4d89277d8c..5bdd6056fc 100644
--- a/epan/dfilter/dfilter-int.h
+++ b/epan/dfilter/dfilter-int.h
@@ -29,6 +29,8 @@ struct epan_dfilter {
char *expanded_text;
GHashTable *references;
char *syntax_tree_str;
+ /* Used to pass arguments to functions. List of Lists (list of registers). */
+ GSList *function_stack;
};
typedef struct {
diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c
index 39adb1cedd..ba0b36a2d1 100644
--- a/epan/dfilter/dfilter.c
+++ b/epan/dfilter/dfilter.c
@@ -188,6 +188,8 @@ dfilter_new(GPtrArray *deprecated)
if (deprecated)
df->deprecated = g_ptr_array_ref(deprecated);
+ df->function_stack = NULL;
+
return df;
}
@@ -223,6 +225,11 @@ dfilter_free(dfilter_t *df)
if (df->deprecated)
g_ptr_array_unref(df->deprecated);
+ if (df->function_stack != NULL) {
+ ws_critical("Function stack list should be NULL");
+ g_slist_free(df->function_stack);
+ }
+
g_free(df->registers);
g_free(df->attempted_load);
g_free(df->free_registers);
diff --git a/epan/dfilter/dfunctions.c b/epan/dfilter/dfunctions.c
index 6c05f92162..0c5234a201 100644
--- a/epan/dfilter/dfunctions.c
+++ b/epan/dfilter/dfunctions.c
@@ -13,6 +13,7 @@
#include "dfilter-int.h"
#include "dfunctions.h"
#include "sttype-pointer.h"
+#include "semcheck.h"
#include <string.h>
@@ -25,7 +26,7 @@
/* Convert an FT_STRING using a callback function */
static gboolean
-string_walk(GSList **args, guint32 arg_count, 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;
@@ -33,7 +34,7 @@ string_walk(GSList **args, guint32 arg_count, GSList **retval, gchar(*conv_func)
char *s, *c;
ws_assert(arg_count == 1);
- arg1 = args[0];
+ arg1 = args->data;
if (arg1 == NULL)
return FALSE;
@@ -59,28 +60,28 @@ string_walk(GSList **args, guint32 arg_count, GSList **retval, gchar(*conv_func)
/* dfilter function: lower() */
static gboolean
-df_func_lower(GSList **args, guint32 arg_count, GSList **retval)
+df_func_lower(GSList *args, guint32 arg_count, GSList **retval)
{
return string_walk(args, arg_count, retval, g_ascii_tolower);
}
/* dfilter function: upper() */
static gboolean
-df_func_upper(GSList **args, guint32 arg_count, GSList **retval)
+df_func_upper(GSList *args, guint32 arg_count, GSList **retval)
{
return string_walk(args, arg_count, retval, g_ascii_toupper);
}
/* dfilter function: len() */
static gboolean
-df_func_len(GSList **args, guint32 arg_count, GSList **retval)
+df_func_len(GSList *args, guint32 arg_count, GSList **retval)
{
GSList *arg1;
fvalue_t *arg_fvalue;
fvalue_t *ft_len;
ws_assert(arg_count == 1);
- arg1 = args[0];
+ arg1 = args->data;
if (arg1 == NULL)
return FALSE;
@@ -97,14 +98,14 @@ df_func_len(GSList **args, guint32 arg_count, GSList **retval)
/* dfilter function: count() */
static gboolean
-df_func_count(GSList **args, guint32 arg_count, GSList **retval)
+df_func_count(GSList *args, guint32 arg_count, GSList **retval)
{
GSList *arg1;
fvalue_t *ft_ret;
guint32 num_items;
ws_assert(arg_count == 1);
- arg1 = args[0];
+ arg1 = args->data;
if (arg1 == NULL)
return FALSE;
@@ -118,7 +119,7 @@ df_func_count(GSList **args, guint32 arg_count, GSList **retval)
/* dfilter function: string() */
static gboolean
-df_func_string(GSList **args, guint32 arg_count, GSList **retval)
+df_func_string(GSList *args, guint32 arg_count, GSList **retval)
{
GSList *arg1;
fvalue_t *arg_fvalue;
@@ -126,7 +127,7 @@ df_func_string(GSList **args, guint32 arg_count, GSList **retval)
char *s;
ws_assert(arg_count == 1);
- arg1 = args[0];
+ arg1 = args->data;
if (arg1 == NULL)
return FALSE;
@@ -187,17 +188,17 @@ df_func_string(GSList **args, guint32 arg_count, GSList **retval)
}
static gboolean
-df_func_compare(GSList **args, guint32 arg_count, GSList **retval,
+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;
+ GSList *l1, *l2;
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;
+ for (l1 = args, i = 0; i < arg_count; l1 = l1->next, i++) {
+ for (l2 = l1->data; l2 != NULL; l2 = l2->next) {
+ if (fv_ret == NULL || fv_cmp(l2->data, fv_ret)) {
+ fv_ret = l2->data;
}
}
}
@@ -212,20 +213,20 @@ df_func_compare(GSList **args, guint32 arg_count, GSList **retval,
/* Find maximum value. */
static gboolean
-df_func_max(GSList **args, guint32 arg_count, GSList **retval)
+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)
+df_func_min(GSList *args, guint32 arg_count, GSList **retval)
{
return df_func_compare(args, arg_count, retval, fvalue_lt);
}
static gboolean
-df_func_abs(GSList **args, guint32 arg_count, GSList **retval)
+df_func_abs(GSList *args, guint32 arg_count, GSList **retval)
{
GSList *arg1;
fvalue_t *fv_arg, *new_fv;
@@ -233,7 +234,7 @@ df_func_abs(GSList **args, guint32 arg_count, GSList **retval)
GSList *result = NULL;
ws_assert(arg_count == 1);
- arg1 = args[0];
+ arg1 = args->data;
if (arg1 == NULL)
return FALSE;
@@ -263,8 +264,8 @@ df_func_abs(GSList **args, guint32 arg_count, GSList **retval)
/* 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,
+static ftenum_t
+ul_semcheck_is_field_string(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype _U_,
GSList *param_list, stloc_t *func_loc _U_)
{
header_field_info *hfinfo;
@@ -277,14 +278,14 @@ ul_semcheck_is_field_string(dfwork_t *dfw, const char *func_name,
if (stnode_type_id(st_node) == STTYPE_FIELD) {
hfinfo = stnode_data(st_node);
if (IS_FT_STRING(hfinfo->type)) {
- return;
+ return FT_STRING;
}
}
FAIL(dfw, st_node, "Only string type fields can be used as parameter for %s()", func_name);
}
-static void
-ul_semcheck_is_field(dfwork_t *dfw, const char *func_name,
+static ftenum_t
+ul_semcheck_is_field(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype _U_,
GSList *param_list, stloc_t *func_loc _U_)
{
ws_assert(g_slist_length(param_list) == 1);
@@ -293,13 +294,13 @@ ul_semcheck_is_field(dfwork_t *dfw, const char *func_name,
dfw_resolve_unparsed(dfw, st_node);
if (stnode_type_id(st_node) == STTYPE_FIELD)
- return;
+ return FT_UINT32;
FAIL(dfw, st_node, "Only fields can be used as parameter for %s()", func_name);
}
-static void
-ul_semcheck_string_param(dfwork_t *dfw, const char *func_name,
+static ftenum_t
+ul_semcheck_string_param(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype _U_,
GSList *param_list, stloc_t *func_loc _U_)
{
header_field_info *hfinfo;
@@ -344,7 +345,7 @@ ul_semcheck_string_param(dfwork_t *dfw, const char *func_name,
case FT_FCWWN:
case FT_IEEE_11073_SFLOAT:
case FT_IEEE_11073_FLOAT:
- return;
+ return FT_STRING;
default:
break;
}
@@ -354,109 +355,126 @@ ul_semcheck_string_param(dfwork_t *dfw, const char *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)
+static ftenum_t
+ul_semcheck_compare(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
+ GSList *param_list, stloc_t *func_loc _U_)
{
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 (stnode_type_id(arg) == STTYPE_ARITHMETIC) {
+ ftype = check_arithmetic_expr(dfw, arg, lhs_ftype);
+ }
+ else if (stnode_type_id(arg) == STTYPE_LITERAL && lhs_ftype != FT_NONE) {
+ fv = dfilter_fvalue_from_literal(dfw, lhs_ftype, arg, FALSE, NULL);
+ stnode_replace(arg, STTYPE_FVALUE, fv);
+ ftype = fvalue_type_ftenum(fv);
+ }
+ else if (stnode_type_id(arg) == STTYPE_FUNCTION) {
+ ftype = check_function(dfw, arg, lhs_ftype);
+ }
+ else {
+ 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));
+ FAIL(dfw, arg, "Argument '%s' (FT_NONE) is not valid for %s()",
+ stnode_todisplay(arg), func_name);
}
- for (l = param_list; l != NULL; l = l->next) {
+ for (l = param_list->next; 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 (stnode_type_id(arg) == STTYPE_ARITHMETIC) {
+ ft_arg = check_arithmetic_expr(dfw, arg, ftype);
+ }
+ else if (stnode_type_id(arg) == STTYPE_LITERAL && ftype != FT_NONE) {
+ fv = dfilter_fvalue_from_literal(dfw, ftype, arg, FALSE, NULL);
+ stnode_replace(arg, STTYPE_FVALUE, fv);
+ ft_arg = fvalue_type_ftenum(fv);
}
+ else if (stnode_type_id(arg) == STTYPE_FUNCTION) {
+ ft_arg = check_function(dfw, arg, ftype);
+ }
+ else {
+ ft_arg = sttype_pointer_ftenum(arg);
+ }
+
if (ft_arg == FT_NONE) {
- dfilter_fail_throw(dfw, func_loc,
- "Argument '%s' (FT_NONE) is not valid for %s()",
+ FAIL(dfw, arg, "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);
+ FAIL(dfw, arg, "Arguments to '%s' must have the same type (expected %s, got %s)",
+ func_name, ftype_name(ftype), ftype_name(ft_arg));
}
if (!ftype_can_cmp(ft_arg)) {
- dfilter_fail_throw(dfw, func_loc,
- "Argument '%s' to '%s' cannot be ordered",
+ FAIL(dfw, arg, "Argument '%s' to '%s' cannot be ordered",
stnode_todisplay(arg), func_name);
}
}
+ return ftype;
}
-static void
-ul_semcheck_absolute_value(dfwork_t *dfw, const char *func_name,
+static ftenum_t
+ul_semcheck_absolute_value(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
GSList *param_list, stloc_t *func_loc _U_)
{
ws_assert(g_slist_length(param_list) == 1);
stnode_t *st_node;
ftenum_t ftype;
- const header_field_info *hfinfo;
+ fvalue_t *fv;
st_node = param_list->data;
dfw_resolve_unparsed(dfw, st_node);
- switch (stnode_type_id(st_node)) {
- case STTYPE_FIELD:
- case STTYPE_REFERENCE:
- hfinfo = stnode_data(st_node);
- ftype = hfinfo->type;
- break;
- default:
- FAIL(dfw, st_node, "Type %s is not valid for %s",
- stnode_type_name(st_node), func_name);
+ if (stnode_type_id(st_node) == STTYPE_ARITHMETIC) {
+ ftype = check_arithmetic_expr(dfw, st_node, lhs_ftype);
+ }
+ else if (stnode_type_id(st_node) == STTYPE_LITERAL && lhs_ftype != FT_NONE) {
+ fv = dfilter_fvalue_from_literal(dfw, lhs_ftype, st_node, FALSE, NULL);
+ stnode_replace(st_node, STTYPE_FVALUE, fv);
+ ftype = fvalue_type_ftenum(fv);
+ }
+ else if (stnode_type_id(st_node) == STTYPE_FUNCTION) {
+ ftype = check_function(dfw, st_node, lhs_ftype);
+ }
+ else {
+ ftype = sttype_pointer_ftenum(st_node);
}
+ if (ftype == FT_NONE) {
+ FAIL(dfw, st_node, "Type %s is not valid for %s",
+ stnode_type_name(st_node), func_name);
+ }
if (!ftype_can_is_negative(ftype)) {
FAIL(dfw, st_node, "'%s' is not a valid argument to '%s'()",
stnode_todisplay(st_node), func_name);
}
+ return ftype;
}
/* The table of all display-filter functions */
static df_func_def_t
df_functions[] = {
- { "lower", df_func_lower, FT_STRING, 1, 1, ul_semcheck_is_field_string },
- { "upper", df_func_upper, FT_STRING, 1, 1, ul_semcheck_is_field_string },
- { "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, 0, 1, 0, ul_semcheck_compare },
- { "min", df_func_min, 0, 1, 0, ul_semcheck_compare },
- { "abs", df_func_abs, 0, 1, 1, ul_semcheck_absolute_value },
- { NULL, NULL, FT_NONE, 0, 0, NULL }
+ { "lower", df_func_lower, 1, 1, ul_semcheck_is_field_string },
+ { "upper", df_func_upper, 1, 1, ul_semcheck_is_field_string },
+ { "len", df_func_len, 1, 1, ul_semcheck_is_field },
+ { "count", df_func_count, 1, 1, ul_semcheck_is_field },
+ { "string", df_func_string, 1, 1, ul_semcheck_string_param },
+ { "max", df_func_max, 1, 0, ul_semcheck_compare },
+ { "min", df_func_min, 1, 0, ul_semcheck_compare },
+ { "abs", df_func_abs, 1, 1, ul_semcheck_absolute_value },
+ { NULL, NULL, 0, 0, NULL }
};
/* Lookup a display filter function record by name */
diff --git a/epan/dfilter/dfunctions.h b/epan/dfilter/dfunctions.h
index 60cae3a33e..71157ea00e 100644
--- a/epan/dfilter/dfunctions.h
+++ b/epan/dfilter/dfunctions.h
@@ -17,10 +17,10 @@
/* Functions take any number of arguments and return 1. */
/* The run-time logic of the dfilter function */
-typedef gboolean (*DFFuncType)(GSList **arg_list, guint32 arg_count, 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,
+typedef ftenum_t (*DFSemCheckType)(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
GSList *param_list, stloc_t *func_loc);
/* This is a "function definition" record, holding everything
@@ -28,7 +28,6 @@ typedef void (*DFSemCheckType)(dfwork_t *dfw, const char *func_name,
typedef struct {
const char *name;
DFFuncType function;
- ftenum_t retval_ftype; /* 0 means return value is the same as input argument(s) */
guint min_nargs;
guint max_nargs; /* 0 for no limit */
DFSemCheckType semcheck_param_function;
diff --git a/epan/dfilter/dfvm.c b/epan/dfilter/dfvm.c
index 5e0ef1521c..17c611711e 100644
--- a/epan/dfilter/dfvm.c
+++ b/epan/dfilter/dfvm.c
@@ -17,6 +17,46 @@
static void
debug_register(GSList *reg, guint32 num);
+const char *
+dfvm_opcode_tostr(dfvm_opcode_t code)
+{
+ switch (code) {
+ case IF_TRUE_GOTO: return "IF_TRUE_GOTO";
+ case IF_FALSE_GOTO: return "IF_FALSE_GOTO";
+ case CHECK_EXISTS: return "CHECK_EXISTS";
+ case NOT: return "NOT";
+ case RETURN: return "RETURN";
+ case READ_TREE: return "READ_TREE";
+ case READ_REFERENCE: return "READ_REFERENCE";
+ case PUT_FVALUE: return "PUT_FVALUE";
+ case ALL_EQ: return "ALL_EQ";
+ case ANY_EQ: return "ANY_EQ";
+ case ALL_NE: return "ALL_NE";
+ case ANY_NE: return "ANY_NE";
+ case ANY_GT: return "ANY_GT";
+ case ANY_GE: return "ANY_GE";
+ case ANY_LT: return "ANY_LT";
+ case ANY_LE: return "ANY_LE";
+ case ANY_ZERO: return "ANY_ZERO";
+ case ALL_ZERO: return "ALL_ZERO";
+ case ANY_CONTAINS: return "ANY_CONTAINS";
+ case ANY_MATCHES: return "ANY_MATCHES";
+ case MK_RANGE: return "MK_RANGE";
+ case MK_BITWISE_AND: return "MK_BITWISE_AND";
+ case MK_MINUS: return "MK_MINUS";
+ case DFVM_ADD: return "DFVM_ADD";
+ case DFVM_SUBTRACT: return "DFVM_SUBTRACT";
+ case DFVM_MULTIPLY: return "DFVM_MULTIPLY";
+ case DFVM_DIVIDE: return "DFVM_DIVIDE";
+ case DFVM_MODULO: return "DFMV_MODULO";
+ case CALL_FUNCTION: return "CALL_FUNCTION";
+ case STACK_PUSH: return "STACK_PUSH";
+ case STACK_POP: return "STACK_POP";
+ case ANY_IN_RANGE: return "ANY_IN_RANGE";
+ }
+ return "(fix-opcode-string)";
+}
+
dfvm_insn_t*
dfvm_insn_new(dfvm_opcode_t op)
{
@@ -148,6 +188,14 @@ dfvm_value_new_pcre(ws_regex_t *re)
return v;
}
+dfvm_value_t*
+dfvm_value_new_guint(guint num)
+{
+ dfvm_value_t *v = dfvm_value_new(INTEGER);
+ v->value.numeric = num;
+ return v;
+}
+
char *
dfvm_value_tostr(dfvm_value_t *v)
{
@@ -187,6 +235,23 @@ dfvm_value_tostr(dfvm_value_t *v)
return s;
}
+static GSList *
+dump_str_stack_push(GSList *stack, const char *str)
+{
+ return g_slist_prepend(stack, g_strdup(str));
+}
+
+static GSList *
+dump_str_stack_pop(GSList *stack)
+{
+ char *str;
+
+ str = stack->data;
+ stack = g_slist_delete_link(stack, stack);
+ g_free(str);
+ return stack;
+}
+
char *
dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references)
{
@@ -198,6 +263,8 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references)
GHashTableIter ref_iter;
gpointer key, value;
char *str;
+ GSList *stack_print = NULL, *l;
+ guint i;
buf = wmem_strbuf_new(alloc, NULL);
@@ -240,16 +307,27 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references)
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);
- }
- for (guint32 i = 1; i <= arg4->value.numeric; i++) {
- wmem_strbuf_append_printf(buf, ", reg#%"G_GUINT32_FORMAT,
- arg3->value.numeric + i);
+ for (l = stack_print, i = 0; i < arg3->value.numeric; i++, l = l->next) {
+ if (l != stack_print) {
+ wmem_strbuf_append(buf, ", ");
+ }
+ wmem_strbuf_append(buf, l->data);
}
wmem_strbuf_append_printf(buf, ") -> %s\n", arg2_str);
break;
+ case STACK_PUSH:
+ wmem_strbuf_append_printf(buf, "%05d STACK_PUSH\t%s\n", id, arg1_str);
+ stack_print = dump_str_stack_push(stack_print, arg1_str);
+ break;
+
+ case STACK_POP:
+ wmem_strbuf_append_printf(buf, "%05d STACK_POP\t%s\n", id, arg1_str);
+ for (i = 0; i < arg1->value.numeric; i ++) {
+ stack_print = dump_str_stack_pop(stack_print);
+ }
+ break;
+
case MK_RANGE:
wmem_strbuf_append_printf(buf, "%05d MK_RANGE\t\t%s[%s] -> %s\n",
id, arg1_str, arg3_str, arg2_str);
@@ -639,13 +717,8 @@ any_matches(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2)
}
static gboolean
-any_in_range(dfilter_t *df, dfvm_value_t *arg1,
- dfvm_value_t *arg_low, dfvm_value_t *arg_high)
+any_in_range_internal(GSList *list1, fvalue_t *low, fvalue_t *high)
{
- GSList *list1 = df->registers[arg1->value.numeric];
- fvalue_t *low = arg_low->value.fvalue;
- fvalue_t *high = arg_high->value.fvalue;
-
while (list1) {
if (fvalue_ge(list1->data, low) &&
fvalue_le(list1->data, high)) {
@@ -656,6 +729,39 @@ any_in_range(dfilter_t *df, dfvm_value_t *arg1,
return FALSE;
}
+static gboolean
+any_in_range(dfilter_t *df, dfvm_value_t *arg1,
+ dfvm_value_t *arg_low, dfvm_value_t *arg_high)
+{
+ GSList *list1 = df->registers[arg1->value.numeric];
+ GSList *_low, *_high;
+ fvalue_t *low, *high;
+
+ if (arg_low->type == REGISTER) {
+ _low = df->registers[arg_low->value.numeric];
+ ws_assert(g_slist_length(_low) == 1);
+ low = _low->data;
+ }
+ else if (arg_low->type == FVALUE) {
+ low = arg_low->value.fvalue;
+ }
+ else {
+ ws_assert_not_reached();
+ }
+ if (arg_high->type == REGISTER) {
+ _high = df->registers[arg_high->value.numeric];
+ ws_assert(g_slist_length(_high) == 1);
+ high = _high->data;
+ }
+ else if (arg_high->type == FVALUE) {
+ high = arg_high->value.fvalue;
+ }
+ else {
+ ws_assert_not_reached();
+ }
+ return any_in_range_internal(list1, low, high);
+}
+
/* Clear registers that were populated during evaluation.
* If we created the values, then these will be freed as well. */
static void
@@ -716,19 +822,18 @@ mk_range(dfilter_t *df, dfvm_value_t *from_arg, dfvm_value_t *to_arg,
*/
static gboolean
call_function(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2,
- dfvm_value_t *arg3, dfvm_value_t *arg4)
+ dfvm_value_t *arg3)
{
df_func_def_t *funcdef;
GSList *retval = NULL;
gboolean accum;
- guint32 reg_return, reg_first_arg, more_args_count;
+ guint32 reg_return, arg_count;
funcdef = arg1->value.funcdef;
reg_return = arg2->value.numeric;
- reg_first_arg = arg3->value.numeric;
- more_args_count = arg4->value.numeric;
+ arg_count = arg3->value.numeric;
- accum = funcdef->function(&df->registers[reg_first_arg], 1 + more_args_count, &retval);
+ accum = funcdef->function(df->function_stack, arg_count, &retval);
/* Write return registers. */
df->registers[reg_return] = retval;
@@ -892,6 +997,42 @@ put_fvalue(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *to_arg)
df->free_registers[to_arg->value.numeric] = NULL;
}
+static void
+stack_push(dfilter_t *df, dfvm_value_t *arg1)
+{
+ GSList *arg;
+
+ if (arg1->type == FVALUE) {
+ arg = g_slist_prepend(NULL, arg1->value.fvalue);
+ }
+ else if (arg1->type == REGISTER) {
+ arg = g_slist_copy(df->registers[arg1->value.numeric]);
+ }
+ else {
+ ws_assert_not_reached();
+ }
+ df->function_stack = g_slist_prepend(df->function_stack, arg);
+}
+
+static void
+stack_pop(dfilter_t *df, dfvm_value_t *arg1)
+{
+ guint count;
+ GSList *reg;
+
+ count = arg1->value.numeric;
+
+ for (guint i = 0; i < count; i++) {
+ /* Free top of stack and register contained there. The register
+ * contentes are not owned by us. */
+ reg = df->function_stack->data;
+ /* Free the list but not the data it contains. */
+ g_slist_free(reg);
+ /* remove top of stack */
+ df->function_stack = g_slist_delete_link(df->function_stack, df->function_stack);
+ }
+}
+
gboolean
dfvm_apply(dfilter_t *df, proto_tree *tree)
{
@@ -901,7 +1042,6 @@ dfvm_apply(dfilter_t *df, proto_tree *tree)
dfvm_value_t *arg1;
dfvm_value_t *arg2;
dfvm_value_t *arg3 = NULL;
- dfvm_value_t *arg4 = NULL;
header_field_info *hfinfo;
ws_assert(tree);
@@ -915,7 +1055,8 @@ dfvm_apply(dfilter_t *df, proto_tree *tree)
arg1 = insn->arg1;
arg2 = insn->arg2;
arg3 = insn->arg3;
- arg4 = insn->arg4;
+
+ ws_noisy("ID: %d; OP: %s", id, dfvm_opcode_tostr(insn->op));
switch (insn->op) {
case CHECK_EXISTS:
@@ -945,7 +1086,15 @@ dfvm_apply(dfilter_t *df, proto_tree *tree)
break;
case CALL_FUNCTION:
- accum = call_function(df, arg1, arg2, arg3, arg4);
+ accum = call_function(df, arg1, arg2, arg3);
+ break;
+
+ case STACK_PUSH:
+ stack_push(df, arg1);
+ break;
+
+ case STACK_POP:
+ stack_pop(df, arg1);
break;
case MK_RANGE:
diff --git a/epan/dfilter/dfvm.h b/epan/dfilter/dfvm.h
index 565e5568fd..c29608ed50 100644
--- a/epan/dfilter/dfvm.h
+++ b/epan/dfilter/dfvm.h
@@ -76,10 +76,15 @@ typedef enum {
DFVM_DIVIDE,
DFVM_MODULO,
CALL_FUNCTION,
+ STACK_PUSH,
+ STACK_POP,
ANY_IN_RANGE
} dfvm_opcode_t;
+const char *
+dfvm_opcode_tostr(dfvm_opcode_t code);
+
typedef struct {
int id;
dfvm_opcode_t op;
@@ -122,6 +127,9 @@ dfvm_value_new_funcdef(df_func_def_t *funcdef);
dfvm_value_t*
dfvm_value_new_pcre(ws_regex_t *re);
+dfvm_value_t*
+dfvm_value_new_guint(guint num);
+
void
dfvm_dump(FILE *f, dfilter_t *df);
diff --git a/epan/dfilter/gencode.c b/epan/dfilter/gencode.c
index 7a4470e750..6b6c7a6821 100644
--- a/epan/dfilter/gencode.c
+++ b/epan/dfilter/gencode.c
@@ -36,9 +36,44 @@ dfw_append_insn(dfwork_t *dfw, dfvm_insn_t *insn)
g_ptr_array_add(dfw->insns, insn);
}
+static void
+dfw_append_stack_push(dfwork_t *dfw, dfvm_value_t *arg1)
+{
+ dfvm_insn_t *insn;
+
+ insn = dfvm_insn_new(STACK_PUSH);
+ insn->arg1 = dfvm_value_ref(arg1);
+ dfw_append_insn(dfw, insn);
+}
+
+static void
+dfw_append_stack_pop(dfwork_t *dfw, guint count)
+{
+ dfvm_insn_t *insn;
+ dfvm_value_t *val;
+
+ insn = dfvm_insn_new(STACK_POP);
+ val = dfvm_value_new_guint(count);
+ insn->arg1 = dfvm_value_ref(val);
+ dfw_append_insn(dfw, insn);
+}
+
+static dfvm_value_t *
+dfw_append_jump(dfwork_t *dfw)
+{
+ dfvm_insn_t *insn;
+ dfvm_value_t *jmp;
+
+ insn = dfvm_insn_new(IF_FALSE_GOTO);
+ jmp = dfvm_value_new(INSN_NUMBER);
+ insn->arg1 = dfvm_value_ref(jmp);
+ dfw_append_insn(dfw, insn);
+ return jmp;
+}
+
/* returns register number */
static dfvm_value_t *
-dfw_append_read_tree(dfwork_t *dfw, header_field_info *hfinfo, gboolean reuse_register)
+dfw_append_read_tree(dfwork_t *dfw, header_field_info *hfinfo)
{
dfvm_insn_t *insn;
int reg = -1;
@@ -56,19 +91,13 @@ dfw_append_read_tree(dfwork_t *dfw, header_field_info *hfinfo, gboolean reuse_re
* can re-use registers. */
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++;
- }
+ /*
+ * 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++;
@@ -169,7 +198,7 @@ dfw_append_mk_range(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr)
}
/* returns register number */
-static dfvm_value_t *
+_U_ static dfvm_value_t *
dfw_append_put_fvalue(dfwork_t *dfw, fvalue_t *fv)
{
dfvm_insn_t *insn;
@@ -190,11 +219,11 @@ static dfvm_value_t *
dfw_append_function(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr)
{
GSList *params;
+ GSList *params_jumps = NULL;
dfvm_value_t *jmp;
dfvm_insn_t *insn;
- dfvm_value_t *reg_val, *val1, *val3, *val4, *val_arg;
- guint32 reg_first, more_args_count;
- stnode_t *arg;
+ dfvm_value_t *reg_val, *val1, *val3, *val_arg;
+ guint count;
/* Create the new DFVM instruction */
insn = dfvm_insn_new(CALL_FUNCTION);
@@ -206,40 +235,22 @@ dfw_append_function(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr)
/* Create input arguments */
params = sttype_function_params(node);
ws_assert(params);
- val3 = dfw_append_read_tree(dfw, stnode_steal_data(params->data), FALSE);
- insn->arg3 = dfvm_value_ref(val3);
-
- params = params->next;
- reg_first = val3->value.numeric;
- more_args_count = 0;
+ 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);
- break;
- default:
- ws_assert_not_reached();
- }
- more_args_count++;
+ val_arg = gen_entity(dfw, params->data, &params_jumps);
+ /* If a parameter fails to generate jump here.
+ * Note: stack_push NULL register is valid. */
+ g_slist_foreach(params_jumps, fixup_jumps, dfw);
+ g_slist_free(params_jumps);
+ params_jumps = NULL;
+ dfw_append_stack_push(dfw, val_arg);
+ count++;
params = params->next;
}
- val4 = dfvm_value_new(INTEGER);
- val4->value.numeric = more_args_count;
- insn->arg4 = dfvm_value_ref(val4);
-
+ val3 = dfvm_value_new_guint(count);
+ insn->arg3 = dfvm_value_ref(val3);
dfw_append_insn(dfw, insn);
-
- /* There is no jump if READ_TREE fails for a function parameter. It
- * is up to the function to return TRUE/FALSE for any combination
- * of (missing or not) arguments. */
+ dfw_append_stack_pop(dfw, count);
/* We need another instruction to jump to another exit
* place, if the call() of our function failed for some reaosn */
@@ -422,30 +433,19 @@ static dfvm_value_t *
gen_entity(dfwork_t *dfw, stnode_t *st_arg, GSList **jumps_ptr)
{
sttype_id_t e_type;
- dfvm_insn_t *insn;
- dfvm_value_t *val, *jmp;
+ dfvm_value_t *val;
header_field_info *hfinfo;
e_type = stnode_type_id(st_arg);
if (e_type == STTYPE_FIELD) {
hfinfo = stnode_data(st_arg);
- val = dfw_append_read_tree(dfw, hfinfo, TRUE);
-
- insn = dfvm_insn_new(IF_FALSE_GOTO);
- jmp = dfvm_value_new(INSN_NUMBER);
- insn->arg1 = dfvm_value_ref(jmp);
- dfw_append_insn(dfw, insn);
- *jumps_ptr = g_slist_prepend(*jumps_ptr, jmp);
+ val = dfw_append_read_tree(dfw, hfinfo);
+ *jumps_ptr = g_slist_prepend(*jumps_ptr, dfw_append_jump(dfw));
}
else if (e_type == STTYPE_REFERENCE) {
hfinfo = stnode_data(st_arg);
val = dfw_append_read_reference(dfw, hfinfo);
-
- insn = dfvm_insn_new(IF_FALSE_GOTO);
- jmp = dfvm_value_new(INSN_NUMBER);
- insn->arg1 = dfvm_value_ref(jmp);
- dfw_append_insn(dfw, insn);
- *jumps_ptr = g_slist_prepend(*jumps_ptr, jmp);
+ *jumps_ptr = g_slist_prepend(*jumps_ptr, dfw_append_jump(dfw));
}
else if (e_type == STTYPE_FVALUE) {
val = dfvm_value_new_fvalue(stnode_steal_data(st_arg));
@@ -463,7 +463,7 @@ gen_entity(dfwork_t *dfw, stnode_t *st_arg, GSList **jumps_ptr)
val = gen_arithmetic(dfw, st_arg, jumps_ptr);
}
else {
- /* printf("sttype_id is %u\n", (unsigned)e_type); */
+ WS_DEBUG_HERE("sttype is %s", stnode_type_name(st_arg));
ws_assert_not_reached();
}
return val;
diff --git a/epan/dfilter/grammar.lemon b/epan/dfilter/grammar.lemon
index c13b640c55..2cd63af9f5 100644
--- a/epan/dfilter/grammar.lemon
+++ b/epan/dfilter/grammar.lemon
@@ -343,12 +343,12 @@ function(F) ::= UNPARSED(U) LPAREN RPAREN.
F = new_function(dfw, U);
}
-function_params(P) ::= entity(E).
+function_params(P) ::= arithmetic_expr(E).
{
P = g_slist_append(NULL, E);
}
-function_params(P) ::= function_params(L) COMMA entity(E).
+function_params(P) ::= function_params(L) COMMA arithmetic_expr(E).
{
P = g_slist_append(L, E);
}
diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c
index 838d2d847c..df984fcdeb 100644
--- a/epan/dfilter/semcheck.c
+++ b/epan/dfilter/semcheck.c
@@ -38,13 +38,6 @@
static void
semcheck(dfwork_t *dfw, stnode_t *st_node);
-static void
-check_function(dfwork_t *dfw, stnode_t *st_node);
-
-static
-ftenum_t
-check_arithmetic_expr(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype);
-
static fvalue_t *
mk_fvalue_from_val_string(dfwork_t *dfw, header_field_info *hfinfo, const char *s);
@@ -552,7 +545,7 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
}
static void
-check_drange_sanity(dfwork_t *dfw, stnode_t *st)
+check_drange_sanity(dfwork_t *dfw, stnode_t *st, ftenum_t lhs_ftype)
{
stnode_t *entity1;
header_field_info *hfinfo1;
@@ -573,8 +566,7 @@ check_drange_sanity(dfwork_t *dfw, stnode_t *st)
hfinfo1->abbrev, ftype_pretty_name(ftype1));
}
} else if (stnode_type_id(entity1) == STTYPE_FUNCTION) {
- check_function(dfw, entity1);
- ftype1 = sttype_function_retval_ftype(entity1);
+ ftype1 = check_function(dfw, entity1, lhs_ftype);
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.",
@@ -582,7 +574,7 @@ check_drange_sanity(dfwork_t *dfw, stnode_t *st)
}
} else if (stnode_type_id(entity1) == STTYPE_RANGE) {
/* Should this be rejected instead? */
- check_drange_sanity(dfw, entity1);
+ check_drange_sanity(dfw, entity1, lhs_ftype);
} else {
FAIL(dfw, entity1, "Range is not supported for entity %s",
stnode_todisplay(entity1));
@@ -604,8 +596,8 @@ convert_to_bytes(stnode_t *arg)
sttype_range_set1(arg, entity1, rn);
}
-static void
-check_function(dfwork_t *dfw, stnode_t *st_node)
+ftenum_t
+check_function(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype)
{
df_func_def_t *funcdef;
GSList *params;
@@ -625,7 +617,7 @@ check_function(dfwork_t *dfw, stnode_t *st_node)
funcdef->name, funcdef->max_nargs);
}
- funcdef->semcheck_param_function(dfw, funcdef->name, params,
+ return funcdef->semcheck_param_function(dfw, funcdef->name, lhs_ftype, params,
stnode_location(st_node));
}
@@ -718,7 +710,7 @@ again:
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
}
else if (type2 == STTYPE_RANGE) {
- check_drange_sanity(dfw, st_arg2);
+ check_drange_sanity(dfw, st_arg2, ftype1);
if (!is_bytes_type(ftype1)) {
if (!ftype_can_slice(ftype1)) {
FAIL(dfw, st_arg1, "\"%s\" is a %s and cannot be converted into a sequence of bytes.",
@@ -731,8 +723,7 @@ again:
}
}
else if (type2 == STTYPE_FUNCTION) {
- check_function(dfw, st_arg2);
- ftype2 = sttype_function_retval_ftype(st_arg2);
+ ftype2 = check_function(dfw, st_arg2, ftype1);
if (!compatible_ftypes(ftype1, ftype2)) {
FAIL(dfw, st_arg2, "%s (type=%s) and return value of %s() (type=%s) are not of compatible types.",
@@ -780,7 +771,7 @@ check_relation_LHS_RANGE(dfwork_t *dfw, test_op_t st_op,
LOG_NODE(st_node);
- check_drange_sanity(dfw, st_arg1);
+ check_drange_sanity(dfw, st_arg1, FT_NONE);
again:
type2 = stnode_type_id(st_arg2);
@@ -821,11 +812,10 @@ again:
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
}
else if (type2 == STTYPE_RANGE) {
- check_drange_sanity(dfw, st_arg2);
+ check_drange_sanity(dfw, st_arg2, FT_BYTES);
}
else if (type2 == STTYPE_FUNCTION) {
- check_function(dfw, st_arg2);
- ftype2 = sttype_function_retval_ftype(st_arg2);
+ ftype2 = check_function(dfw, st_arg2, FT_BYTES);
if (!is_bytes_type(ftype2)) {
if (!ftype_can_slice(ftype2)) {
@@ -874,8 +864,7 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, test_op_t st_op,
LOG_NODE(st_node);
- check_function(dfw, st_arg1);
- ftype1 = sttype_function_retval_ftype(st_arg1);
+ ftype1 = check_function(dfw, st_arg1, FT_NONE);
if (!can_func(ftype1)) {
FAIL(dfw, st_arg1, "Function %s (type=%s) cannot participate in %s comparison.",
@@ -922,7 +911,7 @@ again:
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
}
else if (type2 == STTYPE_RANGE) {
- check_drange_sanity(dfw, st_arg2);
+ check_drange_sanity(dfw, st_arg2, ftype1);
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.",
@@ -935,8 +924,7 @@ again:
}
}
else if (type2 == STTYPE_FUNCTION) {
- check_function(dfw, st_arg2);
- ftype2 = sttype_function_retval_ftype(st_arg2);
+ ftype2 = check_function(dfw, st_arg2, ftype1);
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.",
@@ -1241,11 +1229,10 @@ check_arithmetic_entity(dfwork_t *dfw, stnode_t *st_arg, ftenum_t lhs_ftype)
ftype = hfinfo->type;
}
else if (type == STTYPE_FUNCTION) {
- check_function(dfw, st_arg);
- ftype = sttype_function_retval_ftype(st_arg);
+ ftype = check_function(dfw, st_arg, lhs_ftype);
}
else if (type == STTYPE_RANGE) {
- check_drange_sanity(dfw, st_arg);
+ check_drange_sanity(dfw, st_arg, lhs_ftype);
ftype = FT_BYTES;
}
diff --git a/epan/dfilter/semcheck.h b/epan/dfilter/semcheck.h
index 8c29281982..733bd2ed0d 100644
--- a/epan/dfilter/semcheck.h
+++ b/epan/dfilter/semcheck.h
@@ -14,5 +14,10 @@
gboolean
dfw_semcheck(dfwork_t *dfw);
+ftenum_t
+check_arithmetic_expr(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype);
+
+ftenum_t
+check_function(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype);
#endif
diff --git a/epan/dfilter/sttype-function.c b/epan/dfilter/sttype-function.c
index bc1c6021f2..fd0ed657b0 100644
--- a/epan/dfilter/sttype-function.c
+++ b/epan/dfilter/sttype-function.c
@@ -60,14 +60,20 @@ function_tostr(const void *data, gboolean pretty)
ws_assert(def);
- g_string_printf(repr, "%s: ", def->name);
- while (params != NULL) {
- ws_assert(params->data);
- g_string_append(repr, stnode_tostr(params->data, pretty));
- params = params->next;
- if (params != NULL) {
- g_string_append(repr, ", ");
+ if (pretty) {
+ g_string_printf(repr, "%s(", def->name);
+ while (params != NULL) {
+ ws_assert(params->data);
+ g_string_append(repr, stnode_tostr(params->data, pretty));
+ params = params->next;
+ if (params != NULL) {
+ g_string_append(repr, ", ");
+ }
}
+ g_string_append_c(repr, ')');
+ }
+ else {
+ g_string_printf(repr, "%s#%u", def->name, g_slist_length(params));
}
return g_string_free(repr, FALSE);
@@ -119,23 +125,6 @@ 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)
{
diff --git a/epan/dfilter/sttype-function.h b/epan/dfilter/sttype-function.h
index 48294ce2d7..6f1cb3e8ce 100644
--- a/epan/dfilter/sttype-function.h
+++ b/epan/dfilter/sttype-function.h
@@ -21,8 +21,6 @@ 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. */
diff --git a/epan/dfilter/sttype-test.c b/epan/dfilter/sttype-test.c
index 13c0040ee3..faef9f9a43 100644
--- a/epan/dfilter/sttype-test.c
+++ b/epan/dfilter/sttype-test.c
@@ -64,12 +64,12 @@ test_free(gpointer value)
g_free(test);
}
-static const char *
-test_todisplay(test_op_t op)
+static char *
+test_todisplay(const test_t *test)
{
const char *s = "<notset>";
- switch(op) {
+ switch(test->op) {
case TEST_OP_NOT:
s = "!";
break;
@@ -135,15 +135,15 @@ test_todisplay(test_op_t op)
s = "<uninitialized>";
break;
}
- return s;
+ return g_strdup(s);
}
-static const char *
-test_todebug(test_op_t op)
+static char *
+test_todebug(const test_t *test)
{
const char *s = "<notset>";
- switch(op) {
+ switch(test->op) {
case TEST_OP_NOT:
s = "TEST_NOT";
break;
@@ -211,7 +211,8 @@ test_todebug(test_op_t op)
s = "<uninitialized>";
break;
}
- return s;
+
+ return g_strdup(s);
}
static char *
@@ -219,13 +220,10 @@ test_tostr(const void *value, gboolean pretty)
{
const test_t *test = value;
ws_assert_magic(test, TEST_MAGIC);
- const char *s;
if (pretty)
- s = test_todisplay(test->op);
- else
- s = test_todebug(test->op);
- return g_strdup(s);
+ return test_todisplay(test);
+ return test_todebug(test);
}
static int
diff --git a/epan/dfilter/syntax-tree.c b/epan/dfilter/syntax-tree.c
index bd72a74222..36c73cc1b4 100644
--- a/epan/dfilter/syntax-tree.c
+++ b/epan/dfilter/syntax-tree.c
@@ -15,7 +15,6 @@
#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"
@@ -213,22 +212,6 @@ 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)
{
@@ -397,6 +380,7 @@ static void
visit_tree(wmem_strbuf_t *buf, stnode_t *node, int level)
{
stnode_t *left, *right;
+ GSList *params;
if (stnode_type_id(node) == STTYPE_TEST ||
stnode_type_id(node) == STTYPE_ARITHMETIC) {
@@ -417,6 +401,18 @@ visit_tree(wmem_strbuf_t *buf, stnode_t *node, int level)
ws_assert_not_reached();
}
}
+ else if (stnode_type_id(node) == STTYPE_FUNCTION) {
+ wmem_strbuf_append_printf(buf, "%s:\n", stnode_todebug(node));
+ params = sttype_function_params(node);
+ while (params) {
+ indent(buf, level + 1);
+ visit_tree(buf, params->data, level + 1);
+ if (params->next != NULL) {
+ wmem_strbuf_append_c(buf, '\n');
+ }
+ params = params->next;
+ }
+ }
else {
wmem_strbuf_append(buf, stnode_todebug(node));
}
diff --git a/epan/dfilter/syntax-tree.h b/epan/dfilter/syntax-tree.h
index 796c70d349..9e4912e00f 100644
--- a/epan/dfilter/syntax-tree.h
+++ b/epan/dfilter/syntax-tree.h
@@ -138,9 +138,6 @@ 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);