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.
This commit is contained in:
João Valverde 2022-04-04 23:42:52 +01:00
parent d91734ab6a
commit c98df5eef5
11 changed files with 106 additions and 40 deletions

View File

@ -131,7 +131,7 @@ main(int argc, char **argv)
text = get_args_as_string(argc, argv, 1); text = get_args_as_string(argc, argv, 1);
/* Compile it */ /* Compile it */
if (!dfilter_compile(text, &df, &err_msg)) { if (!dfilter_compile2(text, &df, &err_msg, TRUE)) {
fprintf(stderr, "dftest: %s\n", err_msg); fprintf(stderr, "dftest: %s\n", err_msg);
g_free(err_msg); g_free(err_msg);
epan_cleanup(); epan_cleanup();
@ -139,10 +139,14 @@ main(int argc, char **argv)
exit(2); exit(2);
} }
if (df == NULL) if (df == NULL) {
printf("Filter is empty\n"); 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_dump(df);
}
dfilter_free(df); dfilter_free(df);
epan_cleanup(); epan_cleanup();

View File

@ -28,6 +28,7 @@ struct epan_dfilter {
GPtrArray *deprecated; GPtrArray *deprecated;
char *expanded_text; char *expanded_text;
GHashTable *references; GHashTable *references;
char *syntax_tree_str;
}; };
typedef struct { typedef struct {

View File

@ -208,6 +208,7 @@ dfilter_free(dfilter_t *df)
g_free(df->attempted_load); g_free(df->attempted_load);
g_free(df->free_registers); g_free(df->free_registers);
g_free(df->expanded_text); g_free(df->expanded_text);
g_free(df->syntax_tree_str);
g_free(df); g_free(df);
} }
@ -338,7 +339,8 @@ add_deprecated_token(dfwork_t *dfw, const char *token)
gboolean gboolean
dfilter_compile_real(const gchar *text, dfilter_t **dfp, 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; gchar *expanded_text;
int token; int token;
@ -349,6 +351,7 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp,
YY_BUFFER_STATE in_buffer; YY_BUFFER_STATE in_buffer;
gboolean failure = FALSE; gboolean failure = FALSE;
unsigned token_count = 0; unsigned token_count = 0;
char *tree_str;
ws_assert(dfp); ws_assert(dfp);
*dfp = NULL; *dfp = NULL;
@ -462,14 +465,20 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp,
*dfp = NULL; *dfp = NULL;
} }
else { 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*/ /* Check semantics and do necessary type conversion*/
if (!dfw_semcheck(dfw)) { if (!dfw_semcheck(dfw)) {
goto FAILURE; 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 */ /* Create bytecode */
dfw_gencode(dfw); dfw_gencode(dfw);
@ -484,6 +493,17 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp,
dfilter->references = dfw->references; dfilter->references = dfw->references;
dfw->references = NULL; 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 */ /* Initialize run-time space */
dfilter->num_registers = dfw->next_register; dfilter->num_registers = dfw->next_register;
dfilter->registers = g_new0(GSList *, dfilter->num_registers); 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 void
dfilter_log_full(const char *domain, enum ws_log_level level, dfilter_log_full(const char *domain, enum ws_log_level level,
const char *file, long line, const char *func, 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); char *str = dfvm_dump_str(NULL, df, TRUE);
if (G_UNLIKELY(msg == NULL)) 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 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); g_free(str);
} }

View File

@ -49,10 +49,14 @@ dfilter_cleanup(void);
WS_DLL_PUBLIC WS_DLL_PUBLIC
gboolean gboolean
dfilter_compile_real(const gchar *text, dfilter_t **dfp, 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) \ #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 /* Frees all memory used by dfilter, and frees
* the dfilter itself. */ * the dfilter itself. */
@ -91,6 +95,16 @@ WS_DLL_PUBLIC
void void
dfilter_dump(dfilter_t *df); 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 */ /* Print bytecode of dfilter to log */
WS_DLL_PUBLIC WS_DLL_PUBLIC
void void

View File

@ -195,9 +195,7 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references)
buf = wmem_strbuf_new(alloc, NULL); buf = wmem_strbuf_new(alloc, NULL);
wmem_strbuf_append_printf(buf, "Filter: %s\n", df->expanded_text); wmem_strbuf_append(buf, "Instructions:\n");
wmem_strbuf_append(buf, "\nInstructions:\n");
length = df->insns->len; length = df->insns->len;
for (id = 0; id < length; id++) { for (id = 0; id < length; id++) {

View File

@ -60,7 +60,7 @@ function_tostr(const void *data, gboolean pretty)
ws_assert(def); ws_assert(def);
g_string_printf(repr, "%s(", def->name); g_string_printf(repr, "%s: ", def->name);
while (params != NULL) { while (params != NULL) {
ws_assert(params->data); ws_assert(params->data);
g_string_append(repr, stnode_tostr(params->data, pretty)); 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(repr, ", ");
} }
} }
g_string_append_c(repr, ')');
return g_string_free(repr, FALSE); return g_string_free(repr, FALSE);
} }

View File

@ -46,7 +46,7 @@ sttype_fvalue_tostr(const void *data, gboolean pretty)
if (pretty) if (pretty)
repr = g_strdup(s); repr = g_strdup(s);
else 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); g_free(s);
return repr; return repr;
} }

View File

@ -187,25 +187,25 @@ test_todebug(test_op_t op)
s = "TEST_LE"; s = "TEST_LE";
break; break;
case OP_BITWISE_AND: case OP_BITWISE_AND:
s = "BITWISE_AND"; s = "OP_BITWISE_AND";
break; break;
case OP_UNARY_MINUS: case OP_UNARY_MINUS:
s = "UNARY_MINUS"; s = "OP_UNARY_MINUS";
break; break;
case OP_ADD: case OP_ADD:
s = "ADD"; s = "OP_ADD";
break; break;
case OP_SUBTRACT: case OP_SUBTRACT:
s = "SUBTRACT"; s = "OP_SUBTRACT";
break; break;
case OP_MULTIPLY: case OP_MULTIPLY:
s = "MULTIPLY"; s = "OP_MULTIPLY";
break; break;
case OP_DIVIDE: case OP_DIVIDE:
s = "DIVIDE"; s = "OP_DIVIDE";
break; break;
case OP_MODULO: case OP_MODULO:
s = "MODULO"; s = "OP_MODULO";
break; break;
case TEST_OP_NOTZERO: case TEST_OP_NOTZERO:
s = "TEST_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); ws_assert(num_operands(op) == 1);
test->op = op; test->op = op;
test->val1 = val1; test->val1 = val1;
test->val2 = NULL;
} }
void void
@ -310,6 +311,7 @@ sttype_test_set1_args(stnode_t *node, stnode_t *val1)
ws_assert(num_operands(test->op) == 1); ws_assert(num_operands(test->op) == 1);
test->val1 = val1; test->val1 = val1;
test->val2 = NULL;
} }
void void

View File

@ -266,11 +266,12 @@ _node_tostr(stnode_t *node, gboolean pretty)
if (pretty) if (pretty)
return s; return s;
if (stnode_type_id(node) == STTYPE_TEST) { if (stnode_type_id(node) == STTYPE_TEST ||
stnode_type_id(node) == STTYPE_ARITHMETIC) {
repr = s; repr = s;
} }
else { 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); g_free(s);
} }
@ -382,6 +383,7 @@ indent(wmem_strbuf_t *buf, int level)
for (int i = 0; i < level * 2; i++) { for (int i = 0; i < level * 2; i++) {
wmem_strbuf_append_c(buf, ' '); wmem_strbuf_append_c(buf, ' ');
} }
wmem_strbuf_append_printf(buf, "% 2d ", level);
} }
static void static void
@ -392,45 +394,54 @@ visit_tree(wmem_strbuf_t *buf, stnode_t *node, int level)
if (stnode_type_id(node) == STTYPE_TEST || if (stnode_type_id(node) == STTYPE_TEST ||
stnode_type_id(node) == STTYPE_BITWISE || stnode_type_id(node) == STTYPE_BITWISE ||
stnode_type_id(node) == STTYPE_ARITHMETIC) { 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); sttype_test_get(node, NULL, &left, &right);
if (left && right) { if (left && right) {
wmem_strbuf_append_c(buf, '\n');
indent(buf, level + 1); indent(buf, level + 1);
wmem_strbuf_append(buf, "LHS = ");
visit_tree(buf, left, level + 1); visit_tree(buf, left, level + 1);
wmem_strbuf_append_c(buf, '\n'); wmem_strbuf_append_c(buf, '\n');
indent(buf, level + 1); indent(buf, level + 1);
wmem_strbuf_append(buf, "RHS = ");
visit_tree(buf, right, level + 1); visit_tree(buf, right, level + 1);
wmem_strbuf_append(buf, "\n");
indent(buf, level);
} }
else if (left) { else if (left) {
visit_tree(buf, left, level); indent(buf, level + 1);
visit_tree(buf, left, level + 1);
} }
else if (right) { else if (right) {
visit_tree(buf, right, level); ws_assert_not_reached();
} }
wmem_strbuf_append(buf, ")");
} }
else { else {
wmem_strbuf_append(buf, stnode_todebug(node)); 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 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)) if (!ws_log_msg_is_active(LOG_DOMAIN_DFILTER, level))
return; 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, ws_log_write_always_full(LOG_DOMAIN_DFILTER, level, NULL, -1, NULL,
"%s:\n%s", msg, wmem_strbuf_get_str(buf)); "%s:\n%s", msg, str);
wmem_strbuf_destroy(buf);
if (cache_ptr) {
*cache_ptr = str;
}
else {
g_free(str);
}
} }
/* /*

View File

@ -189,8 +189,11 @@ log_test_full(enum ws_log_level level,
} while (0) } while (0)
#endif #endif
char *
dump_syntax_tree_str(stnode_t *root);
void 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 #ifdef WS_DISABLE_DEBUG
#define ws_assert_magic(obj, mnum) (void)0 #define ws_assert_magic(obj, mnum) (void)0

View File

@ -280,6 +280,8 @@ libwireshark.so.0 libwireshark0 #MINVER#
dfilter_load_field_references@Base 3.7.0 dfilter_load_field_references@Base 3.7.0
dfilter_log_full@Base 3.7.0 dfilter_log_full@Base 3.7.0
dfilter_macro_get_uat@Base 1.9.1 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 disable_name_resolution@Base 1.99.9
display_epoch_time@Base 1.9.1 display_epoch_time@Base 1.9.1
display_signed_time@Base 1.9.1 display_signed_time@Base 1.9.1