From 49934c1d14640b2ca85baeb49ddb32bf045d8a77 Mon Sep 17 00:00:00 2001 From: John Thacker Date: Mon, 12 Feb 2024 20:23:37 -0500 Subject: [PATCH] dfilter: Add a flag to return field values for the tree root In many grammatical contexts fields are only tested for existence instead of loading the values into a register, because that's all that is needed to determine if a filter passes or not. Add a dfilter option to load the field values from the tree and return them when a field (including field at a certain protocol layer) is the root of the filter syntax tree. This is useful for columns, especially for parsing columns defined with the layer operator, but it can't completely replace the current custom column handling because we don't yet return exactly which hfinfo was present, if more than one has the same abbreviation, and it's possible for fields with the same abbreviation to have different strings, and hence different "resolved" values. $ ./run/dftest -s "@ip.proto#1" Filter: @ip.proto#1 Syntax tree: 0 FIELD(@ip.proto#[1:1] ) Instructions: 0000 CHECK_EXISTS_R ip.proto#[1:1] 0001 RETURN $ ./run/dftest -s "@ip.proto#1" --return-vals Filter: @ip.proto#1 Syntax tree: 0 FIELD(@ip.proto#[1:1] ) Instructions: 0000 READ_TREE_R @ip.proto#[1:1] -> R0 0001 NO_OP 0002 RETURN R0 Related to #18588 --- dftest.c | 10 +++++++++- epan/dfilter/dfilter.h | 3 +++ epan/dfilter/gencode.c | 24 +++++++++++++++++++++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/dftest.c b/dftest.c index a40f25f9b6..32f0cad244 100644 --- a/dftest.c +++ b/dftest.c @@ -49,6 +49,7 @@ static int opt_debug_level = 0; /* currently up to 2 */ static int opt_flex = 0; static int opt_lemon = 0; static int opt_syntax_tree = 0; +static int opt_return_vals = 0; static int opt_timer = 0; static long opt_optimize = 1; static int opt_show_types = 0; @@ -108,6 +109,7 @@ print_usage(int status) fprintf(fp, " -s, --syntax print syntax tree\n"); fprintf(fp, " -m --macros print saved macros\n"); fprintf(fp, " -t, --timer print elapsed compilation time\n"); + fprintf(fp, " -r --return-vals return field values for the tree root\n"); fprintf(fp, " -0, --optimize=0 do not optimize (check syntax)\n"); fprintf(fp, " --types show field value types\n"); /* NOTE: References are loaded during runtime and dftest only does compilation. @@ -216,6 +218,8 @@ compile_filter(const char *text, dfilter_t **dfp) df_flags |= DF_DEBUG_FLEX; if (opt_lemon) df_flags |= DF_DEBUG_LEMON; + if (opt_return_vals) + df_flags |= DF_RETURN_VALUES; start = g_get_monotonic_time(); ok = dfilter_compile_full(text, dfp, &df_err, df_flags, "dftest"); @@ -278,7 +282,7 @@ main(int argc, char **argv) ws_init_version_info("DFTest", NULL, NULL); - const char *optstring = "hvdDflsmtV0"; + const char *optstring = "hvdDflsmrtV0"; static struct ws_option long_options[] = { { "help", ws_no_argument, 0, 'h' }, { "version", ws_no_argument, 0, 'v' }, @@ -289,6 +293,7 @@ main(int argc, char **argv) { "macros", ws_no_argument, 0, 'm' }, { "timer", ws_no_argument, 0, 't' }, { "verbose", ws_no_argument, 0, 'V' }, + { "return-vals", ws_no_argument, 0, 'r' }, { "optimize", ws_required_argument, 0, 1000 }, { "types", ws_no_argument, 0, 2000 }, { "refs", ws_no_argument, 0, 3000 }, @@ -335,6 +340,9 @@ main(int argc, char **argv) case 't': opt_timer = 1; break; + case 'r': + opt_return_vals = 1; + break; case '0': opt_optimize = 0; break; diff --git a/epan/dfilter/dfilter.h b/epan/dfilter/dfilter.h index 3f606091e0..50ac0076b8 100644 --- a/epan/dfilter/dfilter.h +++ b/epan/dfilter/dfilter.h @@ -73,6 +73,9 @@ dfilter_expand(const char *expr, df_error_t **err_ret); #define DF_DEBUG_FLEX (1U << 3) /* Enable debug trace for lemon. */ #define DF_DEBUG_LEMON (1U << 4) +/* If the root of the syntax tree is a field, load and return the field values. + * By default the field is only checked for existence. */ +#define DF_RETURN_VALUES (1U << 5) /* Compiles a string to a dfilter_t. * On success, sets the dfilter* pointed to by dfp diff --git a/epan/dfilter/gencode.c b/epan/dfilter/gencode.c index 8d2248d55a..d9cb43f9ff 100644 --- a/epan/dfilter/gencode.c +++ b/epan/dfilter/gencode.c @@ -657,6 +657,18 @@ gen_exists(dfwork_t *dfw, stnode_t *st_node) } } +static dfvm_value_t* +gen_field(dfwork_t *dfw, stnode_t *st_node) +{ + dfvm_value_t *val1; + GSList *jumps = NULL; + + val1 = gen_entity(dfw, st_node, &jumps); + g_slist_foreach(jumps, fixup_jumps, dfw); + g_slist_free(jumps); + return val1; +} + static dfvm_value_t* gen_notzero(dfwork_t *dfw, stnode_t *st_node) { @@ -805,12 +817,22 @@ static dfvm_value_t* gencode(dfwork_t *dfw, stnode_t *st_node) { dfvm_value_t* val = NULL; + /* If the root of the tree is a field, load and return the + * values if we were asked to do so. If not, or anywhere + * other than the root, just test for existence. + */ + bool return_val = dfw->flags & DF_RETURN_VALUES; + dfw->flags &= ~DF_RETURN_VALUES; switch (stnode_type_id(st_node)) { case STTYPE_TEST: gen_test(dfw, st_node); break; case STTYPE_FIELD: - gen_exists(dfw, st_node); + if (return_val) { + val = gen_field(dfw, st_node); + } else { + gen_exists(dfw, st_node); + } break; case STTYPE_ARITHMETIC: case STTYPE_FUNCTION: