dfilter: Display syntax tree for debugging

Use wslog to output debug information. Being able to control
it at runtime is a big advantage.

We extend the syntax tree nodes with a method to return a
canonical string representation.

Add a routine to walk the tree and return an textual representation
for debugging purposes.
This commit is contained in:
João Valverde 2021-09-26 16:28:39 +01:00
parent 1883487241
commit 3ea2a61f2a
14 changed files with 358 additions and 52 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -20,6 +20,7 @@ sttype_register_integer(void)
"INTEGER",
NULL,
NULL,
NULL,
NULL
};

View File

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

View File

@ -116,7 +116,8 @@ sttype_register_range(void)
"RANGE",
range_new,
range_free,
range_dup
range_dup,
NULL
};
sttype_register(&range_type);

View File

@ -65,6 +65,7 @@ sttype_register_set(void)
"SET",
NULL,
sttype_set_free,
NULL,
NULL
};

View File

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

View File

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

View File

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

View File

@ -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)) { \

View File

@ -32,6 +32,8 @@
#define LOG_DOMAIN_EPAN "Epan"
#define LOG_DOMAIN_DFILTER "DFilter"
#define LOG_DOMAIN_WSUTIL "WSUtil"
#define LOG_DOMAIN_QTUI "GUI"

View File

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