From c98df5eef5e6ff23c165d19f3a2d325c0720c42a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Valverde?= Date: Mon, 4 Apr 2022 23:42:52 +0100 Subject: [PATCH] dfilter: Print syntax tree using dftest + format enhancements Add argument to dfilter_compile_real() to save syntax tree text representation. Use it with dftest to print syntax tree. Misc debug output format improvements. --- dftest.c | 10 ++++-- epan/dfilter/dfilter-int.h | 1 + epan/dfilter/dfilter.c | 42 ++++++++++++++++++++++--- epan/dfilter/dfilter.h | 18 +++++++++-- epan/dfilter/dfvm.c | 4 +-- epan/dfilter/sttype-function.c | 3 +- epan/dfilter/sttype-pointer.c | 2 +- epan/dfilter/sttype-test.c | 16 +++++----- epan/dfilter/syntax-tree.c | 43 ++++++++++++++++---------- epan/dfilter/syntax-tree.h | 5 ++- packaging/debian/libwireshark0.symbols | 2 ++ 11 files changed, 106 insertions(+), 40 deletions(-) diff --git a/dftest.c b/dftest.c index 8ab3113c6b..3d6b66728e 100644 --- a/dftest.c +++ b/dftest.c @@ -131,7 +131,7 @@ main(int argc, char **argv) text = get_args_as_string(argc, argv, 1); /* Compile it */ - if (!dfilter_compile(text, &df, &err_msg)) { + if (!dfilter_compile2(text, &df, &err_msg, TRUE)) { fprintf(stderr, "dftest: %s\n", err_msg); g_free(err_msg); epan_cleanup(); @@ -139,10 +139,14 @@ main(int argc, char **argv) exit(2); } - if (df == NULL) + if (df == NULL) { printf("Filter is empty\n"); - else + } + else { + printf("Filter text:\n%s\n\n", dfilter_text(df)); + printf("Syntax tree:\n%s\n\n", dfilter_syntax_tree(df)); dfilter_dump(df); + } dfilter_free(df); epan_cleanup(); diff --git a/epan/dfilter/dfilter-int.h b/epan/dfilter/dfilter-int.h index 4b5d6ff9e1..b73cb77ffc 100644 --- a/epan/dfilter/dfilter-int.h +++ b/epan/dfilter/dfilter-int.h @@ -28,6 +28,7 @@ struct epan_dfilter { GPtrArray *deprecated; char *expanded_text; GHashTable *references; + char *syntax_tree_str; }; typedef struct { diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c index a282c147dd..1be1bfb924 100644 --- a/epan/dfilter/dfilter.c +++ b/epan/dfilter/dfilter.c @@ -208,6 +208,7 @@ dfilter_free(dfilter_t *df) g_free(df->attempted_load); g_free(df->free_registers); g_free(df->expanded_text); + g_free(df->syntax_tree_str); g_free(df); } @@ -338,7 +339,8 @@ add_deprecated_token(dfwork_t *dfw, const char *token) gboolean dfilter_compile_real(const gchar *text, dfilter_t **dfp, - gchar **error_ret, const char *caller) + gchar **error_ret, const char *caller, + gboolean save_tree) { gchar *expanded_text; int token; @@ -349,6 +351,7 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp, YY_BUFFER_STATE in_buffer; gboolean failure = FALSE; unsigned token_count = 0; + char *tree_str; ws_assert(dfp); *dfp = NULL; @@ -462,14 +465,20 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp, *dfp = NULL; } else { - log_syntax_tree(LOG_LEVEL_NOISY, dfw->st_root, "Syntax tree before semantic check"); + log_syntax_tree(LOG_LEVEL_NOISY, dfw->st_root, "Syntax tree before semantic check", NULL); /* Check semantics and do necessary type conversion*/ if (!dfw_semcheck(dfw)) { goto FAILURE; } - log_syntax_tree(LOG_LEVEL_NOISY, dfw->st_root, "Syntax tree after successful semantic check"); + /* Cache tree representation in tree_str. */ + tree_str = NULL; + log_syntax_tree(LOG_LEVEL_NOISY, dfw->st_root, "Syntax tree after successful semantic check", &tree_str); + + if (save_tree && tree_str == NULL) { + tree_str = dump_syntax_tree_str(dfw->st_root); + } /* Create bytecode */ dfw_gencode(dfw); @@ -484,6 +493,17 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp, dfilter->references = dfw->references; dfw->references = NULL; + if (save_tree) { + ws_assert(tree_str); + dfilter->syntax_tree_str = tree_str; + tree_str = NULL; + } + else { + dfilter->syntax_tree_str = NULL; + g_free(tree_str); + tree_str = NULL; + } + /* Initialize run-time space */ dfilter->num_registers = dfw->next_register; dfilter->registers = g_new0(GSList *, dfilter->num_registers); @@ -582,6 +602,18 @@ dfilter_dump(dfilter_t *df) } } +const char * +dfilter_text(dfilter_t *df) +{ + return df->expanded_text; +} + +const char * +dfilter_syntax_tree(dfilter_t *df) +{ + return df->syntax_tree_str; +} + void dfilter_log_full(const char *domain, enum ws_log_level level, const char *file, long line, const char *func, @@ -598,9 +630,9 @@ dfilter_log_full(const char *domain, enum ws_log_level level, char *str = dfvm_dump_str(NULL, df, TRUE); if (G_UNLIKELY(msg == NULL)) - ws_log_write_always_full(domain, level, file, line, func, "\n%s", str); + ws_log_write_always_full(domain, level, file, line, func, "Filter:%s\n%s", dfilter_text(df), str); else - ws_log_write_always_full(domain, level, file, line, func, "%s\n%s", msg, str); + ws_log_write_always_full(domain, level, file, line, func, "%s:\nFilter: %s\nInstructions:\n%s", msg, dfilter_text(df), str); g_free(str); } diff --git a/epan/dfilter/dfilter.h b/epan/dfilter/dfilter.h index 03c7d924d4..b7d22f5755 100644 --- a/epan/dfilter/dfilter.h +++ b/epan/dfilter/dfilter.h @@ -49,10 +49,14 @@ dfilter_cleanup(void); WS_DLL_PUBLIC gboolean dfilter_compile_real(const gchar *text, dfilter_t **dfp, - gchar **err_msg, const char *caller); + gchar **err_msg, const char *caller, + gboolean save_tree); #define dfilter_compile(text, dfp, err_msg) \ - dfilter_compile_real(text, dfp, err_msg, __func__) + dfilter_compile_real(text, dfp, err_msg, __func__, FALSE) + +#define dfilter_compile2(text, dfp, err_msg, save_tree) \ + dfilter_compile_real(text, dfp, err_msg, __func__, save_tree) /* Frees all memory used by dfilter, and frees * the dfilter itself. */ @@ -91,6 +95,16 @@ WS_DLL_PUBLIC void dfilter_dump(dfilter_t *df); +/* Text after macro expansion. */ +WS_DLL_PUBLIC +const char * +dfilter_text(dfilter_t *df); + +/* Text representation of syntax tree (if it was saved, NULL oterwise). */ +WS_DLL_PUBLIC +const char * +dfilter_syntax_tree(dfilter_t *df); + /* Print bytecode of dfilter to log */ WS_DLL_PUBLIC void diff --git a/epan/dfilter/dfvm.c b/epan/dfilter/dfvm.c index a6f400b04f..0afe51e48b 100644 --- a/epan/dfilter/dfvm.c +++ b/epan/dfilter/dfvm.c @@ -195,9 +195,7 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references) buf = wmem_strbuf_new(alloc, NULL); - wmem_strbuf_append_printf(buf, "Filter: %s\n", df->expanded_text); - - wmem_strbuf_append(buf, "\nInstructions:\n"); + wmem_strbuf_append(buf, "Instructions:\n"); length = df->insns->len; for (id = 0; id < length; id++) { diff --git a/epan/dfilter/sttype-function.c b/epan/dfilter/sttype-function.c index 4bca4746cb..e4036a30cd 100644 --- a/epan/dfilter/sttype-function.c +++ b/epan/dfilter/sttype-function.c @@ -60,7 +60,7 @@ function_tostr(const void *data, gboolean pretty) ws_assert(def); - g_string_printf(repr, "%s(", def->name); + g_string_printf(repr, "%s: ", def->name); while (params != NULL) { ws_assert(params->data); g_string_append(repr, stnode_tostr(params->data, pretty)); @@ -69,7 +69,6 @@ function_tostr(const void *data, gboolean pretty) g_string_append(repr, ", "); } } - g_string_append_c(repr, ')'); return g_string_free(repr, FALSE); } diff --git a/epan/dfilter/sttype-pointer.c b/epan/dfilter/sttype-pointer.c index 8f51d9cfd4..d4ef382e3c 100644 --- a/epan/dfilter/sttype-pointer.c +++ b/epan/dfilter/sttype-pointer.c @@ -46,7 +46,7 @@ sttype_fvalue_tostr(const void *data, gboolean pretty) if (pretty) repr = g_strdup(s); else - repr = ws_strdup_printf("%s[%s]", fvalue_type_name(fvalue), s); + repr = ws_strdup_printf("%s <%s>", s, fvalue_type_name(fvalue)); g_free(s); return repr; } diff --git a/epan/dfilter/sttype-test.c b/epan/dfilter/sttype-test.c index 1e57bd52eb..4c96f7da8e 100644 --- a/epan/dfilter/sttype-test.c +++ b/epan/dfilter/sttype-test.c @@ -187,25 +187,25 @@ test_todebug(test_op_t op) s = "TEST_LE"; break; case OP_BITWISE_AND: - s = "BITWISE_AND"; + s = "OP_BITWISE_AND"; break; case OP_UNARY_MINUS: - s = "UNARY_MINUS"; + s = "OP_UNARY_MINUS"; break; case OP_ADD: - s = "ADD"; + s = "OP_ADD"; break; case OP_SUBTRACT: - s = "SUBTRACT"; + s = "OP_SUBTRACT"; break; case OP_MULTIPLY: - s = "MULTIPLY"; + s = "OP_MULTIPLY"; break; case OP_DIVIDE: - s = "DIVIDE"; + s = "OP_DIVIDE"; break; case OP_MODULO: - s = "MODULO"; + s = "OP_MODULO"; break; case TEST_OP_NOTZERO: s = "TEST_NOTZERO"; @@ -286,6 +286,7 @@ sttype_test_set1(stnode_t *node, test_op_t op, stnode_t *val1) ws_assert(num_operands(op) == 1); test->op = op; test->val1 = val1; + test->val2 = NULL; } void @@ -310,6 +311,7 @@ sttype_test_set1_args(stnode_t *node, stnode_t *val1) ws_assert(num_operands(test->op) == 1); test->val1 = val1; + test->val2 = NULL; } void diff --git a/epan/dfilter/syntax-tree.c b/epan/dfilter/syntax-tree.c index dd3cd7cb67..c9b13fa1b7 100644 --- a/epan/dfilter/syntax-tree.c +++ b/epan/dfilter/syntax-tree.c @@ -266,11 +266,12 @@ _node_tostr(stnode_t *node, gboolean pretty) if (pretty) return s; - if (stnode_type_id(node) == STTYPE_TEST) { + if (stnode_type_id(node) == STTYPE_TEST || + stnode_type_id(node) == STTYPE_ARITHMETIC) { repr = s; } else { - repr = ws_strdup_printf("%s<%s>", stnode_type_name(node), s); + repr = ws_strdup_printf("%s(%s)", stnode_type_name(node), s); g_free(s); } @@ -382,6 +383,7 @@ indent(wmem_strbuf_t *buf, int level) for (int i = 0; i < level * 2; i++) { wmem_strbuf_append_c(buf, ' '); } + wmem_strbuf_append_printf(buf, "% 2d ", level); } static void @@ -392,45 +394,54 @@ visit_tree(wmem_strbuf_t *buf, stnode_t *node, int level) if (stnode_type_id(node) == STTYPE_TEST || stnode_type_id(node) == STTYPE_BITWISE || stnode_type_id(node) == STTYPE_ARITHMETIC) { - wmem_strbuf_append_printf(buf, "%s(", stnode_todebug(node)); + wmem_strbuf_append_printf(buf, "%s:\n", stnode_todebug(node)); sttype_test_get(node, NULL, &left, &right); if (left && right) { - wmem_strbuf_append_c(buf, '\n'); indent(buf, level + 1); - wmem_strbuf_append(buf, "LHS = "); visit_tree(buf, left, level + 1); wmem_strbuf_append_c(buf, '\n'); indent(buf, level + 1); - wmem_strbuf_append(buf, "RHS = "); visit_tree(buf, right, level + 1); - wmem_strbuf_append(buf, "\n"); - indent(buf, level); } else if (left) { - visit_tree(buf, left, level); + indent(buf, level + 1); + visit_tree(buf, left, level + 1); } else if (right) { - visit_tree(buf, right, level); + ws_assert_not_reached(); } - wmem_strbuf_append(buf, ")"); } else { wmem_strbuf_append(buf, stnode_todebug(node)); } } +char * +dump_syntax_tree_str(stnode_t *root) +{ + wmem_strbuf_t *buf = wmem_strbuf_new(NULL, NULL); + indent(buf, 0); + visit_tree(buf, root, 0); + return wmem_strbuf_finalize(buf); +} + void -log_syntax_tree(enum ws_log_level level, stnode_t *root, const char *msg) +log_syntax_tree(enum ws_log_level level, stnode_t *root, const char *msg, char **cache_ptr) { if (!ws_log_msg_is_active(LOG_DOMAIN_DFILTER, level)) return; - wmem_strbuf_t *buf = wmem_strbuf_new(NULL, NULL); + char *str = dump_syntax_tree_str(root); - visit_tree(buf, root, 0); ws_log_write_always_full(LOG_DOMAIN_DFILTER, level, NULL, -1, NULL, - "%s:\n%s", msg, wmem_strbuf_get_str(buf)); - wmem_strbuf_destroy(buf); + "%s:\n%s", msg, str); + + if (cache_ptr) { + *cache_ptr = str; + } + else { + g_free(str); + } } /* diff --git a/epan/dfilter/syntax-tree.h b/epan/dfilter/syntax-tree.h index c883282434..5a8adbe058 100644 --- a/epan/dfilter/syntax-tree.h +++ b/epan/dfilter/syntax-tree.h @@ -189,8 +189,11 @@ log_test_full(enum ws_log_level level, } while (0) #endif +char * +dump_syntax_tree_str(stnode_t *root); + void -log_syntax_tree(enum ws_log_level, stnode_t *root, const char *msg); +log_syntax_tree(enum ws_log_level, stnode_t *root, const char *msg, char **cache_ptr); #ifdef WS_DISABLE_DEBUG #define ws_assert_magic(obj, mnum) (void)0 diff --git a/packaging/debian/libwireshark0.symbols b/packaging/debian/libwireshark0.symbols index 7fd12a18b9..bd07423221 100644 --- a/packaging/debian/libwireshark0.symbols +++ b/packaging/debian/libwireshark0.symbols @@ -280,6 +280,8 @@ libwireshark.so.0 libwireshark0 #MINVER# dfilter_load_field_references@Base 3.7.0 dfilter_log_full@Base 3.7.0 dfilter_macro_get_uat@Base 1.9.1 + dfilter_syntax_tree@Base 3.7.0 + dfilter_text@Base 3.7.0 disable_name_resolution@Base 1.99.9 display_epoch_time@Base 1.9.1 display_signed_time@Base 1.9.1