forked from osmocom/wireshark
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:
parent
d91734ab6a
commit
c98df5eef5
10
dftest.c
10
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();
|
||||
|
|
|
@ -28,6 +28,7 @@ struct epan_dfilter {
|
|||
GPtrArray *deprecated;
|
||||
char *expanded_text;
|
||||
GHashTable *references;
|
||||
char *syntax_tree_str;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue