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);
/* 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();

View File

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

View File

@ -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);
}

View File

@ -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

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);
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++) {

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
}
/*

View File

@ -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

View File

@ -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