aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/dfilter/dfilter-int.h2
-rw-r--r--epan/dfilter/dfilter.c46
-rw-r--r--epan/dfilter/semcheck.c74
-rw-r--r--epan/dfilter/sttype-function.c18
-rw-r--r--epan/dfilter/sttype-integer.c1
-rw-r--r--epan/dfilter/sttype-pointer.c38
-rw-r--r--epan/dfilter/sttype-range.c3
-rw-r--r--epan/dfilter/sttype-set.c1
-rw-r--r--epan/dfilter/sttype-string.c15
-rw-r--r--epan/dfilter/sttype-test.c63
-rw-r--r--epan/dfilter/syntax-tree.c119
-rw-r--r--epan/dfilter/syntax-tree.h26
-rw-r--r--ws_log_defs.h2
-rw-r--r--wsutil/str_util.h2
14 files changed, 358 insertions, 52 deletions
diff --git a/epan/dfilter/dfilter-int.h b/epan/dfilter/dfilter-int.h
index 648892aed6..7124b2159f 100644
--- a/epan/dfilter/dfilter-int.h
+++ b/epan/dfilter/dfilter-int.h
@@ -73,4 +73,6 @@ dfilter_fail(dfwork_t *dfw, const char *format, ...) G_GNUC_PRINTF(2, 3);
void
DfilterTrace(FILE *TraceFILE, char *zTracePrompt);
+const char *tokenstr(int token);
+
#endif
diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c
index 641d0ff7ed..450ab77dac 100644
--- a/epan/dfilter/dfilter.c
+++ b/epan/dfilter/dfilter.c
@@ -7,7 +7,7 @@
*/
#include "config.h"
-#define WS_LOG_DOMAIN "Dfilter"
+#define WS_LOG_DOMAIN LOG_DOMAIN_DFILTER
#include <stdio.h>
#include <string.h>
@@ -23,6 +23,7 @@
#include "scanner_lex.h"
#include <wsutil/wslog.h>
#include <wsutil/ws_assert.h>
+#include "grammar.h"
#define DFILTER_TOKEN_ID_OFFSET 1
@@ -197,6 +198,44 @@ dfwork_free(dfwork_t *dfw)
g_free(dfw);
}
+const char *tokenstr(int token)
+{
+ switch (token) {
+ case TOKEN_TEST_AND: return "TEST_AND";
+ case TOKEN_TEST_OR: return "TEST_OR";
+ case TOKEN_TEST_EQ: return "TEST_EQ";
+ case TOKEN_TEST_NE: return "TEST_NE";
+ case TOKEN_TEST_LT: return "TEST_LT";
+ case TOKEN_TEST_LE: return "TEST_LE";
+ case TOKEN_TEST_GT: return "TEST_GT";
+ case TOKEN_TEST_GE: return "TEST_GE";
+ case TOKEN_TEST_CONTAINS: return "TEST_CONTAINS";
+ case TOKEN_TEST_MATCHES: return "TEST_MATCHES";
+ case TOKEN_TEST_BITWISE_AND: return "TEST_BITWISE_AND";
+ case TOKEN_TEST_NOT: return "TEST_NOT";
+ case TOKEN_FIELD: return "FIELD";
+ case TOKEN_STRING: return "STRING";
+ case TOKEN_CHARCONST: return "CHARCONST";
+ case TOKEN_UNPARSED: return "UNPARSED";
+ case TOKEN_LBRACKET: return "LBRACKET";
+ case TOKEN_RBRACKET: return "RBRACKET";
+ case TOKEN_COMMA: return "COMMA";
+ case TOKEN_INTEGER: return "INTEGER";
+ case TOKEN_COLON: return "COLON";
+ case TOKEN_HYPHEN: return "HYPHEN";
+ case TOKEN_TEST_IN: return "TEST_IN";
+ case TOKEN_LBRACE: return "LBRACE";
+ case TOKEN_RBRACE: return "RBRACE";
+ case TOKEN_WHITESPACE: return "WHITESPACE";
+ case TOKEN_DOTDOT: return "DOTDOT";
+ case TOKEN_FUNCTION: return "FUNCTION";
+ case TOKEN_LPAREN: return "LPAREN";
+ case TOKEN_RPAREN: return "RPAREN";
+ default: return "<unknown>";
+ }
+ ws_assert_not_reached();
+}
+
gboolean
dfilter_compile(const gchar *text, dfilter_t **dfp, gchar **err_msg)
{
@@ -280,6 +319,8 @@ dfilter_compile(const gchar *text, dfilter_t **dfp, gchar **err_msg)
g_ptr_array_add(deprecated, g_strdup(depr_test));
}
+ ws_debug("Token: %d %s", token, tokenstr(token));
+
/* Give the token to the parser */
Dfilter(ParserObj, token, df_lval, dfw);
/* We've used the stnode_t, so we don't want to free it */
@@ -331,12 +372,15 @@ dfilter_compile(const gchar *text, dfilter_t **dfp, gchar **err_msg)
g_ptr_array_free(deprecated, TRUE);
}
else {
+ log_syntax_tree(LOG_LEVEL_NOISY, dfw->st_root, "Syntax tree before semantic check");
/* Check semantics and do necessary type conversion*/
if (!dfw_semcheck(dfw, deprecated)) {
goto FAILURE;
}
+ log_syntax_tree(LOG_LEVEL_NOISY, dfw->st_root, "Syntax tree after successful semantic check");
+
/* Create bytecode */
dfw_gencode(dfw);
diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c
index fc3ebcfcc0..36595c1f8f 100644
--- a/epan/dfilter/semcheck.c
+++ b/epan/dfilter/semcheck.c
@@ -8,6 +8,8 @@
#include "config.h"
+#define WS_LOG_DOMAIN LOG_DOMAIN_DFILTER
+
#include <string.h>
#include "dfilter-int.h"
@@ -22,21 +24,10 @@
#include <epan/packet.h>
#include <wsutil/ws_assert.h>
+#include <wsutil/wslog.h>
#include <ftypes/ftypes-int.h>
-/* Enable debug logging by defining AM_CFLAGS
- * so that it contains "-DDEBUG_dfilter".
- * Usage: DebugLog(("Error: string=%s\n", str)); */
-
-#ifdef DEBUG_dfilter
-#define DebugLog(x) \
- printf("%s:%u: ", __FILE__, (unsigned int)__LINE__); \
- printf x; \
- fflush(stdout)
-#else
-#define DebugLog(x) ;
-#endif
static void
semcheck(dfwork_t *dfw, stnode_t *st_node, GPtrArray *deprecated);
@@ -411,7 +402,7 @@ dfilter_g_regex_from_string(dfwork_t *dfw, const char *s)
*/
cflags = (GRegexCompileFlags)(cflags | G_REGEX_RAW);
- DebugLog(("Compile regex pattern: '%s'\n", s));
+ ws_debug("Compile regex pattern: %s", s);
pcre = g_regex_new(
s, /* pattern */
@@ -436,11 +427,13 @@ dfilter_g_regex_from_string(dfwork_t *dfw, const char *s)
static void
check_exists(dfwork_t *dfw, stnode_t *st_arg1)
{
-#ifdef DEBUG_dfilter
+#ifndef WS_DISABLE_DEBUG
static guint i = 0;
#endif
- DebugLog((" 4 check_exists() [%u]\n", i++));
+ ws_debug("4 check_exists() [%u]", i++);
+ stnode_log(st_arg1);
+
switch (stnode_type_id(st_arg1)) {
case STTYPE_FIELD:
/* This is OK */
@@ -683,9 +676,9 @@ check_relation_LHS_FIELD(dfwork_t *dfw, const char *relation_string,
ftype1 = hfinfo1->type;
if (stnode_type_id(st_node) == STTYPE_TEST) {
- DebugLog((" 5 check_relation_LHS_FIELD(%s)\n", relation_string));
+ ws_debug("5 check_relation_LHS_FIELD(%s)", relation_string);
} else {
- DebugLog((" 6 check_relation_LHS_FIELD(%s)\n", relation_string));
+ ws_debug("6 check_relation_LHS_FIELD(%s)", relation_string);
}
if (!can_func(ftype1)) {
@@ -871,7 +864,7 @@ check_relation_LHS_STRING(dfwork_t *dfw, const char* relation_string,
type2 = stnode_type_id(st_arg2);
- DebugLog((" 5 check_relation_LHS_STRING()\n"));
+ ws_debug("5 check_relation_LHS_STRING()");
if (type2 == STTYPE_FIELD) {
hfinfo2 = (header_field_info*)stnode_data(st_arg2);
@@ -965,7 +958,7 @@ check_relation_LHS_UNPARSED(dfwork_t *dfw, const char* relation_string,
type2 = stnode_type_id(st_arg2);
- DebugLog((" 5 check_relation_LHS_UNPARSED()\n"));
+ ws_debug("5 check_relation_LHS_UNPARSED()");
if (type2 == STTYPE_FIELD) {
hfinfo2 = (header_field_info*)stnode_data(st_arg2);
@@ -1060,7 +1053,7 @@ check_relation_LHS_RANGE(dfwork_t *dfw, const char *relation_string,
char *s;
int len_range;
- DebugLog((" 5 check_relation_LHS_RANGE(%s)\n", relation_string));
+ ws_debug("5 check_relation_LHS_RANGE(%s)", relation_string);
type2 = stnode_type_id(st_arg2);
entity1 = sttype_range_entity(st_arg1);
@@ -1098,7 +1091,7 @@ check_relation_LHS_RANGE(dfwork_t *dfw, const char *relation_string,
check_drange_sanity(dfw, st_arg1);
if (type2 == STTYPE_FIELD) {
- DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_FIELD)\n"));
+ ws_debug("5 check_relation_LHS_RANGE(type2 = STTYPE_FIELD)");
hfinfo2 = (header_field_info*)stnode_data(st_arg2);
ftype2 = hfinfo2->type;
@@ -1117,7 +1110,7 @@ check_relation_LHS_RANGE(dfwork_t *dfw, const char *relation_string,
}
}
else if (type2 == STTYPE_STRING) {
- DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_STRING)\n"));
+ ws_debug("5 check_relation_LHS_RANGE(type2 = STTYPE_STRING)");
s = (char*)stnode_data(st_arg2);
if (strcmp(relation_string, "matches") == 0) {
/* Convert to a GRegex * */
@@ -1129,7 +1122,6 @@ check_relation_LHS_RANGE(dfwork_t *dfw, const char *relation_string,
} else {
fvalue = dfilter_fvalue_from_string(dfw, FT_BYTES, s);
if (!fvalue) {
- DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_STRING): Could not convert from string!\n"));
THROW(TypeError);
}
new_st = stnode_new(STTYPE_FVALUE, fvalue);
@@ -1138,7 +1130,7 @@ check_relation_LHS_RANGE(dfwork_t *dfw, const char *relation_string,
stnode_free(st_arg2);
}
else if (type2 == STTYPE_UNPARSED) {
- DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_UNPARSED)\n"));
+ ws_debug("5 check_relation_LHS_RANGE(type2 = STTYPE_UNPARSED)");
s = (char*)stnode_data(st_arg2);
len_range = drange_get_total_length(sttype_range_drange(st_arg1));
if (strcmp(relation_string, "matches") == 0) {
@@ -1182,7 +1174,6 @@ check_relation_LHS_RANGE(dfwork_t *dfw, const char *relation_string,
fvalue = dfilter_fvalue_from_unparsed(dfw, FT_BYTES, s, allow_partial_value);
}
if (!fvalue) {
- DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_UNPARSED): Could not convert from string!\n"));
THROW(TypeError);
}
new_st = stnode_new(STTYPE_FVALUE, fvalue);
@@ -1191,7 +1182,7 @@ check_relation_LHS_RANGE(dfwork_t *dfw, const char *relation_string,
stnode_free(st_arg2);
}
else if (type2 == STTYPE_CHARCONST) {
- DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_CHARCONST)\n"));
+ ws_debug("5 check_relation_LHS_RANGE(type2 = STTYPE_CHARCONST)");
s = (char*)stnode_data(st_arg2);
if (strcmp(relation_string, "matches") == 0) {
/* Convert to a GRegex */
@@ -1205,7 +1196,6 @@ check_relation_LHS_RANGE(dfwork_t *dfw, const char *relation_string,
* one-byte byte string. */
fvalue = dfilter_fvalue_from_charconst_string(dfw, FT_BYTES, s, allow_partial_value);
if (!fvalue) {
- DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_UNPARSED): Could not convert from string!\n"));
THROW(TypeError);
}
new_st = stnode_new(STTYPE_FVALUE, fvalue);
@@ -1214,7 +1204,7 @@ check_relation_LHS_RANGE(dfwork_t *dfw, const char *relation_string,
stnode_free(st_arg2);
}
else if (type2 == STTYPE_RANGE) {
- DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_RANGE)\n"));
+ ws_debug("5 check_relation_LHS_RANGE(type2 = STTYPE_RANGE)");
check_drange_sanity(dfw, st_arg2);
}
else if (type2 == STTYPE_FUNCTION) {
@@ -1298,7 +1288,7 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, const char *relation_string,
/* params = */sttype_function_params(st_arg1); /* XXX: is this done for the side-effect ? */
- DebugLog((" 5 check_relation_LHS_FUNCTION(%s)\n", relation_string));
+ ws_debug("5 check_relation_LHS_FUNCTION(%s)", relation_string);
if (!can_func(ftype1)) {
dfilter_fail(dfw, "Function %s (type=%s) cannot participate in '%s' comparison.",
@@ -1415,14 +1405,16 @@ check_relation(dfwork_t *dfw, const char *relation_string,
FtypeCanFunc can_func, stnode_t *st_node,
stnode_t *st_arg1, stnode_t *st_arg2)
{
-#ifdef DEBUG_dfilter
+#ifndef WS_DISABLE_DEBUG
static guint i = 0;
#endif
header_field_info *hfinfo;
stnode_t *new_st;
char *s;
- DebugLog((" 4 check_relation(\"%s\") [%u]\n", relation_string, i++));
+ ws_debug("4 check_relation(\"%s\") [%u]", relation_string, i++);
+ stnode_log(st_arg1);
+ stnode_log(st_arg2);
/* Protocol can only be on LHS (for "contains" or "matches" operators).
* Check to see if protocol is on RHS, and re-interpret it as UNPARSED
@@ -1504,11 +1496,12 @@ check_test(dfwork_t *dfw, stnode_t *st_node, GPtrArray *deprecated)
{
test_op_t st_op, st_arg_op;
stnode_t *st_arg1, *st_arg2;
-#ifdef DEBUG_dfilter
+#ifndef WS_DISABLE_DEBUG
static guint i = 0;
#endif
- DebugLog((" 3 check_test(stnode_t *st_node = %p) [%u]\n", st_node, i));
+ ws_debug("3 check_test(stnode_t *st_node = %p) [%u]\n", st_node, i++);
+ stnode_log(st_node);
sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2);
@@ -1583,7 +1576,6 @@ check_test(dfwork_t *dfw, stnode_t *st_node, GPtrArray *deprecated)
default:
ws_assert_not_reached();
}
- DebugLog((" 3 check_test(stnode_t *st_node = %p) [%u] - End\n", st_node, i++));
}
@@ -1591,10 +1583,11 @@ check_test(dfwork_t *dfw, stnode_t *st_node, GPtrArray *deprecated)
static void
semcheck(dfwork_t *dfw, stnode_t *st_node, GPtrArray *deprecated)
{
-#ifdef DEBUG_dfilter
+#ifndef WS_DISABLE_DEBUG
static guint i = 0;
#endif
- DebugLog((" 2 semcheck(stnode_t *st_node = %p) [%u]\n", st_node, i++));
+ ws_debug("2 semcheck(stnode_t *st_node = %p) [%u]", st_node, i++);
+
/* The parser assures that the top-most syntax-tree
* node will be a TEST node, no matter what. So assert that. */
switch (stnode_type_id(st_node)) {
@@ -1614,11 +1607,12 @@ gboolean
dfw_semcheck(dfwork_t *dfw, GPtrArray *deprecated)
{
volatile gboolean ok_filter = TRUE;
-#ifdef DEBUG_dfilter
+#ifndef WS_DISABLE_DEBUG
static guint i = 0;
#endif
- DebugLog(("1 dfw_semcheck(dfwork_t *dfw = %p) [%u]\n", dfw, i));
+ ws_debug("1 dfw_semcheck(dfwork_t *dfw = %p) [%u]", dfw, i);
+
/* Instead of having to check for errors at every stage of
* the semantic-checking, the semantic-checking code will
* throw an exception if a problem is found. */
@@ -1630,8 +1624,8 @@ dfw_semcheck(dfwork_t *dfw, GPtrArray *deprecated)
}
ENDTRY;
- DebugLog(("1 dfw_semcheck(dfwork_t *dfw = %p) [%u] - Returns %d\n",
- dfw, i++,ok_filter));
+ ws_debug("1 dfw_semcheck(dfwork_t *dfw = %p) [%u] - Returns %d",
+ dfw, i++, ok_filter);
return ok_filter;
}
diff --git a/epan/dfilter/sttype-function.c b/epan/dfilter/sttype-function.c
index 0d0c3ee404..4bc3825239 100644
--- a/epan/dfilter/sttype-function.c
+++ b/epan/dfilter/sttype-function.c
@@ -52,6 +52,21 @@ function_dup(gconstpointer data)
return (gpointer) stfuncrec;
}
+static char *
+function_tostr(const void *data)
+{
+ const function_t *stfuncrec = (const function_t *)data;
+ const df_func_def_t *def = stfuncrec->funcdef;
+ guint args_len = 0;
+
+ ws_assert(def);
+
+ if (stfuncrec->params != NULL)
+ args_len = g_slist_length(stfuncrec->params);
+
+ return g_strdup_printf("%s(n = %u)", def->name, args_len);
+}
+
static void
slist_stnode_free(gpointer data)
{
@@ -118,7 +133,8 @@ sttype_register_function(void)
"FUNCTION",
function_new,
function_free,
- function_dup
+ function_dup,
+ function_tostr
};
sttype_register(&function_type);
diff --git a/epan/dfilter/sttype-integer.c b/epan/dfilter/sttype-integer.c
index c7fd24c656..dc58ce984a 100644
--- a/epan/dfilter/sttype-integer.c
+++ b/epan/dfilter/sttype-integer.c
@@ -20,6 +20,7 @@ sttype_register_integer(void)
"INTEGER",
NULL,
NULL,
+ NULL,
NULL
};
diff --git a/epan/dfilter/sttype-pointer.c b/epan/dfilter/sttype-pointer.c
index 489db05872..452630e75b 100644
--- a/epan/dfilter/sttype-pointer.c
+++ b/epan/dfilter/sttype-pointer.c
@@ -40,6 +40,35 @@ pcre_free(gpointer value)
}
}
+static char *
+fvalue_tostr(const void *data)
+{
+ fvalue_t *fvalue = (fvalue_t*)data;
+
+ char *s, *repr;
+
+ s = fvalue_to_string_repr(NULL, fvalue, FTREPR_DFILTER, BASE_NONE);
+ repr = g_strdup_printf("%s[%s]", fvalue_type_name(fvalue), s);
+ g_free(s);
+ return repr;
+}
+
+static char *
+field_tostr(const void *data)
+{
+ header_field_info *hfinfo = (header_field_info *)data;
+
+ return g_strdup(hfinfo->abbrev);
+}
+
+static char *
+pcre_tostr(const void *data)
+{
+ const GRegex *pcre = (const GRegex *)data;
+
+ return g_strdup(g_regex_get_pattern(pcre));
+}
+
void
sttype_register_pointer(void)
{
@@ -48,21 +77,24 @@ sttype_register_pointer(void)
"FIELD",
NULL,
NULL,
- NULL
+ NULL,
+ field_tostr
};
static sttype_t fvalue_type = {
STTYPE_FVALUE,
"FVALUE",
NULL,
fvalue_free,
- NULL
+ NULL,
+ fvalue_tostr
};
static sttype_t pcre_type = {
STTYPE_PCRE,
"PCRE",
NULL,
pcre_free,
- NULL
+ NULL,
+ pcre_tostr
};
sttype_register(&field_type);
diff --git a/epan/dfilter/sttype-range.c b/epan/dfilter/sttype-range.c
index 448eedf2aa..9b9b256370 100644
--- a/epan/dfilter/sttype-range.c
+++ b/epan/dfilter/sttype-range.c
@@ -116,7 +116,8 @@ sttype_register_range(void)
"RANGE",
range_new,
range_free,
- range_dup
+ range_dup,
+ NULL
};
sttype_register(&range_type);
diff --git a/epan/dfilter/sttype-set.c b/epan/dfilter/sttype-set.c
index 15dfd2afc2..aad28c438a 100644
--- a/epan/dfilter/sttype-set.c
+++ b/epan/dfilter/sttype-set.c
@@ -65,6 +65,7 @@ sttype_register_set(void)
"SET",
NULL,
sttype_set_free,
+ NULL,
NULL
};
diff --git a/epan/dfilter/sttype-string.c b/epan/dfilter/sttype-string.c
index 00ffda5181..bc65e26381 100644
--- a/epan/dfilter/sttype-string.c
+++ b/epan/dfilter/sttype-string.c
@@ -27,6 +27,12 @@ string_free(gpointer value)
g_free(value);
}
+static char *
+string_tostr(const void *data)
+{
+ return g_strdup(data);
+}
+
void
sttype_register_string(void)
@@ -36,7 +42,8 @@ sttype_register_string(void)
"STRING",
string_new,
string_free,
- string_dup
+ string_dup,
+ string_tostr
};
static sttype_t charconst_type = {
@@ -44,7 +51,8 @@ sttype_register_string(void)
"CHARCONST",
string_new,
string_free,
- string_dup
+ string_dup,
+ string_tostr
};
static sttype_t unparsed_type = {
@@ -52,7 +60,8 @@ sttype_register_string(void)
"UNPARSED",
string_new,
string_free,
- string_dup
+ string_dup,
+ string_tostr
};
sttype_register(&string_type);
diff --git a/epan/dfilter/sttype-test.c b/epan/dfilter/sttype-test.c
index 18bfbf5b1c..8fc1e9f447 100644
--- a/epan/dfilter/sttype-test.c
+++ b/epan/dfilter/sttype-test.c
@@ -64,6 +64,66 @@ test_free(gpointer value)
g_free(test);
}
+static char *
+test_tostr(const void *value)
+{
+ const test_t *test = (const test_t *)value;
+ assert_magic(test, TEST_MAGIC);
+
+ const char *s = "<null>";
+
+ switch(test->op) {
+ case TEST_OP_EXISTS:
+ s = "TEST_EXIST";
+ break;
+ case TEST_OP_NOT:
+ s = "TEST_NOT";
+ break;
+ case TEST_OP_AND:
+ s = "TEST_AND";
+ break;
+ case TEST_OP_OR:
+ s = "TEST_OR";
+ break;
+ case TEST_OP_EQ:
+ s = "TEST_EQ";
+ break;
+ case TEST_OP_NE:
+ s = "TEST_NE";
+ break;
+ case TEST_OP_GT:
+ s = "TEST_GT";
+ break;
+ case TEST_OP_GE:
+ s = "TEST_GE";
+ break;
+ case TEST_OP_LT:
+ s = "TEST_LT";
+ break;
+ case TEST_OP_LE:
+ s = "TEST_LE";
+ break;
+ case TEST_OP_BITWISE_AND:
+ s = "TEST_BITAND";
+ break;
+ case TEST_OP_CONTAINS:
+ s = "TEST_CONTAINS";
+ break;
+ case TEST_OP_MATCHES:
+ s = "TEST_MATCHES";
+ break;
+ case TEST_OP_IN:
+ s = "TEST_IN";
+ break;
+ case TEST_OP_UNINITIALIZED:
+ s = "<uninitialized>";
+ break;
+ default:
+ break;
+ }
+ return g_strdup(s);
+}
+
static int
num_operands(test_op_t op)
{
@@ -158,7 +218,8 @@ sttype_register_test(void)
"TEST",
test_new,
test_free,
- test_dup
+ test_dup,
+ test_tostr
};
sttype_register(&test_type);
diff --git a/epan/dfilter/syntax-tree.c b/epan/dfilter/syntax-tree.c
index d9ac1c1fd5..3a8f213c39 100644
--- a/epan/dfilter/syntax-tree.c
+++ b/epan/dfilter/syntax-tree.c
@@ -8,8 +8,15 @@
#include "config.h"
+#define WS_LOG_DOMAIN LOG_DOMAIN_DFILTER
+
+#include <inttypes.h>
#include "syntax-tree.h"
#include <wsutil/ws_assert.h>
+#include <wsutil/wslog.h>
+#include <wsutil/wmem/wmem.h>
+#include <wsutil/str_util.h>
+#include "sttype-test.h"
/* Keep track of sttype_t's via their sttype_id_t number */
static sttype_t* type_list[STTYPE_NUM_TYPES];
@@ -227,6 +234,118 @@ stnode_deprecated(stnode_t *node)
return node->deprecated_token;
}
+char *
+stnode_tostr(stnode_t *node)
+{
+ char *s, *repr;
+
+ if (stnode_type_id(node) == STTYPE_TEST)
+ return node->type->func_tostr(node->data);
+
+ if (stnode_type_id(node) == STTYPE_INTEGER)
+ return g_strdup_printf("%s<%"PRId32">", stnode_type_name(node), stnode_value(node));
+
+ if (node->type->func_tostr == NULL)
+ return g_strdup_printf("%s<FIXME>", stnode_type_name(node));
+
+ s = node->type->func_tostr(node->data);
+ repr = g_strdup_printf("%s<%s>", stnode_type_name(node), s);
+ g_free(s);
+
+ return repr;
+}
+
+static char *
+sprint_node(stnode_t *node)
+{
+ wmem_strbuf_t *buf = wmem_strbuf_new(NULL, NULL);
+ char *s;
+
+ wmem_strbuf_append_printf(buf, "stnode <%p> = {\n", (void *)node);
+ wmem_strbuf_append_printf(buf, "\tmagic = %"PRIx32"\n", node->magic);
+ wmem_strbuf_append_printf(buf, "\ttype = %s\n", stnode_type_name(node));
+ s = node->type->func_tostr(node->data);
+ wmem_strbuf_append_printf(buf, "\tdata = %s\n", s);
+ g_free(s);
+ wmem_strbuf_append_printf(buf, "\tvalue = %"PRId32"\n", node->value);
+ wmem_strbuf_append_printf(buf, "\tinside_brackets = %s\n", true_or_false(node->inside_brackets));
+ wmem_strbuf_append_printf(buf, "\tdeprecated_token = %s\n", node->deprecated_token);
+ wmem_strbuf_append_printf(buf, "}\n");
+ return wmem_strbuf_finalize(buf);
+}
+
+void
+stnode_log_full(enum ws_log_level level,
+ const char *file, int line, const char *func,
+ stnode_t *node, const char *msg)
+{
+ if (!ws_log_msg_is_active(LOG_DOMAIN_DFILTER, level))
+ return;
+
+ char *str = sprint_node(node);
+ ws_log_write_always_full(LOG_DOMAIN_DFILTER, level,
+ file, line, func, "%s:\n%s", msg, str);
+ g_free(str);
+}
+
+static void indent(wmem_strbuf_t *buf, int level)
+{
+ for (int i = 0; i < level * 2; i++) {
+ wmem_strbuf_append_c(buf, ' ');
+ }
+}
+
+static void
+visit_tree(wmem_strbuf_t *buf, stnode_t *node, int level)
+{
+ stnode_t *left, *right;
+ char *str;
+
+ if (stnode_type_id(node) == STTYPE_TEST) {
+ str = stnode_tostr(node);
+ wmem_strbuf_append_printf(buf, "%s(", str);
+ g_free(str);
+ 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);
+ }
+ else if (right) {
+ visit_tree(buf, right, level);
+ }
+ wmem_strbuf_append(buf, ")");
+ }
+ else {
+ str = stnode_tostr(node);
+ wmem_strbuf_append_printf(buf, "%s", str);
+ g_free(str);
+ }
+}
+
+void
+log_syntax_tree(enum ws_log_level level, stnode_t *root, const char *msg)
+{
+ if (!ws_log_msg_is_active(LOG_DOMAIN_DFILTER, level))
+ return;
+
+ wmem_strbuf_t *buf = wmem_strbuf_new(NULL, NULL);
+
+ visit_tree(buf, root, 0);
+ ws_log(LOG_DOMAIN_DFILTER, level, "%s:\n%s", msg, wmem_strbuf_get_str(buf));
+ wmem_strbuf_destroy(buf);
+}
+
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
diff --git a/epan/dfilter/syntax-tree.h b/epan/dfilter/syntax-tree.h
index da2c237521..dd99b3d4c1 100644
--- a/epan/dfilter/syntax-tree.h
+++ b/epan/dfilter/syntax-tree.h
@@ -9,8 +9,11 @@
#ifndef SYNTAX_TREE_H
#define SYNTAX_TREE_H
+#include <stdio.h>
+#include <stdint.h>
#include <glib.h>
#include "cppmagic.h"
+#include "ws_log_defs.h"
/** @file
*/
@@ -34,6 +37,7 @@ typedef enum {
typedef gpointer (*STTypeNewFunc)(gpointer);
typedef gpointer (*STTypeDupFunc)(gconstpointer);
typedef void (*STTypeFreeFunc)(gpointer);
+typedef char* (*STTypeToStrFunc)(gconstpointer);
/* Type information */
@@ -43,17 +47,18 @@ typedef struct {
STTypeNewFunc func_new;
STTypeFreeFunc func_free;
STTypeDupFunc func_dup;
+ STTypeToStrFunc func_tostr;
} sttype_t;
/** Node (type instance) information */
typedef struct {
- guint32 magic;
+ uint32_t magic;
sttype_t *type;
/* This could be made an enum, but I haven't
* set aside to time to do so. */
gpointer data;
- gint32 value;
+ int32_t value;
gboolean inside_brackets;
const char *deprecated_token;
} stnode_t;
@@ -112,6 +117,23 @@ stnode_value(stnode_t *node);
const char *
stnode_deprecated(stnode_t *node);
+char *
+stnode_tostr(stnode_t *node);
+
+void
+stnode_log_full(enum ws_log_level level,
+ const char *file, int line, const char *func,
+ stnode_t *node, const char *msg);
+
+#ifdef WS_DISABLE_DEBUG
+#define stnode_log(node) (void)0;
+#else
+#define stnode_log(node) \
+ stnode_log_full(LOG_LEVEL_NOISY, __FILE__, __LINE__, __func__, node, #node)
+#endif
+
+void log_syntax_tree(enum ws_log_level, stnode_t *root, const char *msg);
+
#define assert_magic(obj, mnum) \
g_assert_true((obj)); \
if ((obj)->magic != (mnum)) { \
diff --git a/ws_log_defs.h b/ws_log_defs.h
index 214f0ae397..b573ffc742 100644
--- a/ws_log_defs.h
+++ b/ws_log_defs.h
@@ -32,6 +32,8 @@
#define LOG_DOMAIN_EPAN "Epan"
+#define LOG_DOMAIN_DFILTER "DFilter"
+
#define LOG_DOMAIN_WSUTIL "WSUtil"
#define LOG_DOMAIN_QTUI "GUI"
diff --git a/wsutil/str_util.h b/wsutil/str_util.h
index 46e75f6d74..a7f56d3553 100644
--- a/wsutil/str_util.h
+++ b/wsutil/str_util.h
@@ -117,6 +117,8 @@ gchar printable_char_or_period(gchar c);
/* To pass one of two strings, singular or plural */
#define plurality(d,s,p) ((d) == 1 ? (s) : (p))
+#define true_or_false(val) ((val) ? "TRUE" : "FALSE")
+
#ifdef __cplusplus
}