Move filter related code to libfilter under libcommon
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Thu, 28 Nov 2019 21:09:16 +0000 (16:09 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 20 Aug 2020 19:58:47 +0000 (15:58 -0400)
Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I006dcac801ce1ec742de3a03f21a1c5f8b698298

40 files changed:
.gitignore
configure.ac
src/bin/lttng/Makefile.am
src/common/Makefile.am
src/common/filter/Makefile.am [new file with mode: 0644]
src/common/filter/filter-ast.h [new file with mode: 0644]
src/common/filter/filter-bytecode.h [new file with mode: 0644]
src/common/filter/filter-grammar-test.c [new file with mode: 0644]
src/common/filter/filter-ir.h [new file with mode: 0644]
src/common/filter/filter-lexer.l [new file with mode: 0644]
src/common/filter/filter-parser.y [new file with mode: 0644]
src/common/filter/filter-symbols.h [new file with mode: 0644]
src/common/filter/filter-visitor-generate-bytecode.c [new file with mode: 0644]
src/common/filter/filter-visitor-generate-ir.c [new file with mode: 0644]
src/common/filter/filter-visitor-ir-check-binary-comparator.c [new file with mode: 0644]
src/common/filter/filter-visitor-ir-check-binary-op-nesting.c [new file with mode: 0644]
src/common/filter/filter-visitor-ir-normalize-glob-patterns.c [new file with mode: 0644]
src/common/filter/filter-visitor-ir-validate-globbing.c [new file with mode: 0644]
src/common/filter/filter-visitor-ir-validate-string.c [new file with mode: 0644]
src/common/filter/filter-visitor-xml.c [new file with mode: 0644]
src/common/filter/memstream.h [new file with mode: 0644]
src/lib/lttng-ctl/Makefile.am
src/lib/lttng-ctl/filter/Makefile.am [deleted file]
src/lib/lttng-ctl/filter/filter-ast.h [deleted file]
src/lib/lttng-ctl/filter/filter-bytecode.h [deleted file]
src/lib/lttng-ctl/filter/filter-grammar-test.c [deleted file]
src/lib/lttng-ctl/filter/filter-ir.h [deleted file]
src/lib/lttng-ctl/filter/filter-lexer.l [deleted file]
src/lib/lttng-ctl/filter/filter-parser.y [deleted file]
src/lib/lttng-ctl/filter/filter-symbols.h [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-generate-bytecode.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-generate-ir.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-ir-check-binary-comparator.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-ir-check-binary-op-nesting.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-ir-normalize-glob-patterns.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-ir-validate-globbing.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-ir-validate-string.c [deleted file]
src/lib/lttng-ctl/filter/filter-visitor-xml.c [deleted file]
src/lib/lttng-ctl/filter/memstream.h [deleted file]
src/lib/lttng-ctl/lttng-ctl.c

index 78c99b7813997809bc482504dbe06b4550302622..49aa0d1c16adcdc7af7c83f0a843a3b7c778f2a7 100644 (file)
@@ -61,11 +61,11 @@ compile_commands.json
 /src/bin/lttng-crash/lttng-crash
 /src/bin/lttng-relayd/lttng-relayd
 /src/lib/lttng-ctl/lttng-ctl.pc
 /src/bin/lttng-crash/lttng-crash
 /src/bin/lttng-relayd/lttng-relayd
 /src/lib/lttng-ctl/lttng-ctl.pc
-/src/lib/lttng-ctl/filter/filter-grammar-test
-/src/lib/lttng-ctl/filter/filter-lexer.c
-/src/lib/lttng-ctl/filter/filter-parser.c
-/src/lib/lttng-ctl/filter/filter-parser.h
-/src/lib/lttng-ctl/filter/filter-parser.output
+/src/common/filter/filter-grammar-test
+/src/common/filter/filter-lexer.c
+/src/common/filter/filter-parser.c
+/src/common/filter/filter-parser.h
+/src/common/filter/filter-parser.output
 
 /extras/bindings/swig/python/lttng.i
 /extras/bindings/swig/python/lttng.py
 
 /extras/bindings/swig/python/lttng.i
 /extras/bindings/swig/python/lttng.py
index 4e186d471ac4bd0f83efe85892401ae9292c3038..c6b83b78aeadf0f09b8ca1b840363b3cb4f7b824 100644 (file)
@@ -1081,7 +1081,7 @@ AC_SUBST(AM_LDFLAGS)
 # In a scenario where lttng-tools is built from a distribution tarball and in a
 # out-of-tree manner, the generated "version.i" has priority on the one from
 # the source (distribution tarball) and must be found first.
 # In a scenario where lttng-tools is built from a distribution tarball and in a
 # out-of-tree manner, the generated "version.i" has priority on the one from
 # the source (distribution tarball) and must be found first.
-AM_CPPFLAGS="-I\$(top_builddir)/include -I\$(top_srcdir)/include -I\$(top_srcdir)/src -include config.h $AM_CPPFLAGS"
+AM_CPPFLAGS="-I\$(top_builddir)/include -I\$(top_srcdir)/include -I\$(top_builddir)/src -I\$(top_srcdir)/src -include config.h $AM_CPPFLAGS"
 AC_SUBST(AM_CPPFLAGS)
 
 lttngincludedir="${includedir}/lttng"
 AC_SUBST(AM_CPPFLAGS)
 
 lttngincludedir="${includedir}/lttng"
@@ -1129,9 +1129,9 @@ AC_CONFIG_FILES([
        src/common/config/Makefile
        src/common/string-utils/Makefile
        src/common/fd-tracker/Makefile
        src/common/config/Makefile
        src/common/string-utils/Makefile
        src/common/fd-tracker/Makefile
+       src/common/filter/Makefile
        src/lib/Makefile
        src/lib/lttng-ctl/Makefile
        src/lib/Makefile
        src/lib/lttng-ctl/Makefile
-       src/lib/lttng-ctl/filter/Makefile
        src/lib/lttng-ctl/lttng-ctl.pc
        src/bin/Makefile
        src/bin/lttng-consumerd/Makefile
        src/lib/lttng-ctl/lttng-ctl.pc
        src/bin/Makefile
        src/bin/lttng-consumerd/Makefile
index d094c5aafc30a146e27514fbe992fcc1b5078f40..a6bd7a9d738372bc5b4f86b5a24add072d24b7d4 100644 (file)
@@ -37,4 +37,5 @@ lttng_LDADD = $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la \
                        $(top_builddir)/src/common/libcommon.la \
                        $(top_builddir)/src/common/config/libconfig.la \
                        $(top_builddir)/src/common/string-utils/libstring-utils.la \
                        $(top_builddir)/src/common/libcommon.la \
                        $(top_builddir)/src/common/config/libconfig.la \
                        $(top_builddir)/src/common/string-utils/libstring-utils.la \
+                       $(top_builddir)/src/common/filter/libfilter.la \
                        $(POPT_LIBS)
                        $(POPT_LIBS)
index c855dcd7a7daffb776b267b0df8804fb10d58d54..6a841e92a703bc82d4f85b73ba228e44dd383157 100644 (file)
@@ -2,7 +2,7 @@
 
 AUTOMAKE_OPTIONS = subdir-objects
 
 
 AUTOMAKE_OPTIONS = subdir-objects
 
-SUBDIRS = string-utils
+SUBDIRS = string-utils filter
 
 # Make sure to always distribute all folders
 # since SUBDIRS is decided at configure time.
 
 # Make sure to always distribute all folders
 # since SUBDIRS is decided at configure time.
@@ -20,8 +20,8 @@ DIST_SUBDIRS = \
        config \
        consumer \
        string-utils \
        config \
        consumer \
        string-utils \
-       fd-tracker
-
+       fd-tracker \
+       filter
 # Common library
 noinst_LTLIBRARIES = libcommon.la
 EXTRA_DIST = mi-lttng-4.0.xsd
 # Common library
 noinst_LTLIBRARIES = libcommon.la
 EXTRA_DIST = mi-lttng-4.0.xsd
@@ -87,7 +87,8 @@ libcommon_la_LIBADD = \
        $(top_builddir)/src/common/config/libconfig.la \
        $(top_builddir)/src/common/compat/libcompat.la \
        $(top_builddir)/src/common/hashtable/libhashtable.la \
        $(top_builddir)/src/common/config/libconfig.la \
        $(top_builddir)/src/common/compat/libcompat.la \
        $(top_builddir)/src/common/hashtable/libhashtable.la \
-       $(top_builddir)/src/common/fd-tracker/libfd-tracker.la
+       $(top_builddir)/src/common/fd-tracker/libfd-tracker.la \
+       $(top_builddir)/src/common/filter/libfilter.la
 
 if BUILD_LIB_COMPAT
 SUBDIRS += compat
 
 if BUILD_LIB_COMPAT
 SUBDIRS += compat
diff --git a/src/common/filter/Makefile.am b/src/common/filter/Makefile.am
new file mode 100644 (file)
index 0000000..cac4cb1
--- /dev/null
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+AM_CPPFLAGS += -I$(srcdir) -I$(builddir)
+
+noinst_PROGRAMS = filter-grammar-test
+noinst_LTLIBRARIES = libfilter.la
+noinst_HEADERS = filter-ast.h \
+               filter-symbols.h
+
+BUILT_SOURCES = filter-parser.h
+
+libfilter_la_SOURCES = \
+       filter-parser.y filter-lexer.l \
+       filter-visitor-xml.c \
+       filter-visitor-generate-ir.c \
+       filter-visitor-ir-check-binary-op-nesting.c \
+       filter-visitor-ir-validate-string.c \
+       filter-visitor-ir-validate-globbing.c \
+       filter-visitor-ir-normalize-glob-patterns.c \
+       filter-visitor-generate-bytecode.c \
+       filter-ast.h \
+       filter-bytecode.h \
+       filter-ir.h \
+       memstream.h
+libfilter_la_CFLAGS = -include filter-symbols.h $(AM_CFLAGS)
+libfilter_la_LIBADD = $(top_builddir)/src/common/string-utils/libstring-utils.la
+
+AM_YFLAGS = -t -d -v -Wno-yacc
+
+# start with empty files to clean
+CLEANFILES =
+
+if HAVE_BISON
+# we have bison: we can clean the generated parser files
+CLEANFILES += filter-parser.c filter-parser.h filter-parser.output
+else # HAVE_BISON
+# create target used to stop the build if we want to build the parser,
+# but we don't have the necessary tool to do so
+ERR_MSG = "Error: Cannot build target because bison is missing."
+ERR_MSG += "Make sure bison is installed and run the configure script again."
+
+filter-parser.c filter-parser.h: filter-parser.y
+       @echo $(ERR_MSG)
+       @false
+
+all-local: filter-parser.c filter-parser.h
+endif # HAVE_BISON
+
+if HAVE_FLEX
+# we have flex: we can clean the generated lexer files
+CLEANFILES += filter-lexer.c
+else # HAVE_FLEX
+# create target used to stop the build if we want to build the lexer,
+# but we don't have the necessary tool to do so
+ERR_MSG = "Error: Cannot build target because flex is missing."
+ERR_MSG += "Make sure flex is installed and run the configure script again."
+
+filter-lexer.c: filter-lexer.l
+       @echo $(ERR_MSG)
+       @false
+
+all-local: filter-lexer.c
+endif # HAVE_FLEX
+
+filter_grammar_test_SOURCES = filter-grammar-test.c
+filter_grammar_test_LDADD = libfilter.la
diff --git a/src/common/filter/filter-ast.h b/src/common/filter/filter-ast.h
new file mode 100644 (file)
index 0000000..29fde10
--- /dev/null
@@ -0,0 +1,188 @@
+#ifndef _FILTER_AST_H
+#define _FILTER_AST_H
+
+/*
+ * filter-ast.h
+ *
+ * LTTng filter AST
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+/*
+ * Note: filter-ast.h should be included before filter-parser.h.
+ */
+
+#include <urcu/list.h>
+#include <stdint.h>
+
+#define printf_debug(fmt, args...)                                     \
+       do {                                                            \
+               if (filter_parser_debug)                                \
+                       fprintf(stdout, "[debug] " fmt, ## args);       \
+       } while (0)
+
+// the parameter name (of the reentrant 'yyparse' function)
+// data is a pointer to a 'SParserParam' structure
+//#define YYPARSE_PARAM        parser_ctx
+
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+extern int filter_parser_debug;
+
+struct filter_node;
+struct filter_parser;
+
+enum node_type {
+       NODE_UNKNOWN = 0,
+       NODE_ROOT,
+
+       NODE_EXPRESSION,
+       NODE_OP,
+       NODE_UNARY_OP,
+
+       NR_NODE_TYPES,
+};
+
+enum op_type {
+       AST_OP_UNKNOWN = 0,
+       AST_OP_MUL,
+       AST_OP_DIV,
+       AST_OP_MOD,
+       AST_OP_PLUS,
+       AST_OP_MINUS,
+       AST_OP_BIT_RSHIFT,
+       AST_OP_BIT_LSHIFT,
+       AST_OP_AND,
+       AST_OP_OR,
+       AST_OP_BIT_AND,
+       AST_OP_BIT_OR,
+       AST_OP_BIT_XOR,
+
+       AST_OP_EQ,
+       AST_OP_NE,
+       AST_OP_GT,
+       AST_OP_LT,
+       AST_OP_GE,
+       AST_OP_LE,
+};
+
+enum unary_op_type {
+       AST_UNARY_UNKNOWN = 0,
+       AST_UNARY_PLUS,
+       AST_UNARY_MINUS,
+       AST_UNARY_NOT,
+       AST_UNARY_BIT_NOT,
+};
+
+enum ast_link_type {
+       AST_LINK_UNKNOWN = 0,
+       AST_LINK_DOT,
+       AST_LINK_RARROW,
+       AST_LINK_BRACKET,
+};
+
+struct filter_node {
+       /*
+        * Parent node is only set on demand by specific visitor.
+        */
+       struct filter_node *parent;
+       struct cds_list_head gc;
+
+       enum node_type type;
+       union {
+               struct {
+               } unknown;
+               struct {
+                       struct filter_node *child;
+               } root;
+               struct {
+                       enum {
+                               AST_EXP_UNKNOWN = 0,
+                               AST_EXP_STRING,
+                               AST_EXP_CONSTANT,
+                               AST_EXP_FLOAT_CONSTANT,
+                               AST_EXP_IDENTIFIER,
+                               AST_EXP_GLOBAL_IDENTIFIER,
+                               AST_EXP_NESTED,
+                       } type;
+                       enum ast_link_type post_op;     /* reverse */
+                       enum ast_link_type pre_op;      /* forward */
+                       union {
+                               const char *string;
+                               uint64_t constant;
+                               double float_constant;
+                               const char *identifier;
+                               /*
+                                * child can be nested.
+                                */
+                               struct filter_node *child;
+                       } u;
+                       /* prev: backward dot/arrow chain (postfix expression) */
+                       struct filter_node *prev;
+                       /* next: forward dot/arrow chain, generated by a visitor. */
+                       struct filter_node *next;
+                       /* next_bracket: linked bracket chain (prefix expression) */
+                       struct filter_node *next_bracket;
+               } expression;
+               struct {
+                       enum op_type type;
+                       struct filter_node *lchild;
+                       struct filter_node *rchild;
+               } op;
+               struct {
+                       enum unary_op_type type;
+                       struct filter_node *child;
+               } unary_op;
+       } u;
+};
+
+struct filter_ast {
+       struct filter_node root;
+       struct cds_list_head allocated_nodes;
+};
+
+const char *node_type(struct filter_node *node);
+
+struct ir_op;
+
+struct filter_parser_ctx {
+       yyscan_t scanner;
+       struct filter_ast *ast;
+       struct cds_list_head allocated_strings;
+       struct ir_op *ir_root;
+       struct lttng_filter_bytecode_alloc *bytecode;
+       struct lttng_filter_bytecode_alloc *bytecode_reloc;
+};
+
+struct filter_parser_ctx *filter_parser_ctx_alloc(FILE *input);
+void filter_parser_ctx_free(struct filter_parser_ctx *parser_ctx);
+int filter_parser_ctx_append_ast(struct filter_parser_ctx *parser_ctx);
+int filter_parser_ctx_create_from_filter_expression(
+               const char *filter_expression, struct filter_parser_ctx **ctxp);
+
+static inline
+struct filter_ast *filter_parser_get_ast(struct filter_parser_ctx *parser_ctx)
+{
+       return parser_ctx->ast;
+}
+
+int filter_visitor_print_xml(struct filter_parser_ctx *ctx, FILE *stream,
+                       int indent);
+int filter_visitor_ir_generate(struct filter_parser_ctx *ctx);
+void filter_ir_free(struct filter_parser_ctx *ctx);
+int filter_visitor_bytecode_generate(struct filter_parser_ctx *ctx);
+void filter_bytecode_free(struct filter_parser_ctx *ctx);
+int filter_visitor_ir_check_binary_op_nesting(struct filter_parser_ctx *ctx);
+int filter_visitor_ir_check_binary_comparator(struct filter_parser_ctx *ctx);
+int filter_visitor_ir_validate_string(struct filter_parser_ctx *ctx);
+int filter_visitor_ir_normalize_glob_patterns(struct filter_parser_ctx *ctx);
+int filter_visitor_ir_validate_globbing(struct filter_parser_ctx *ctx);
+
+#endif /* _FILTER_AST_H */
diff --git a/src/common/filter/filter-bytecode.h b/src/common/filter/filter-bytecode.h
new file mode 100644 (file)
index 0000000..053bb08
--- /dev/null
@@ -0,0 +1,243 @@
+#ifndef _FILTER_BYTECODE_H
+#define _FILTER_BYTECODE_H
+
+/*
+ * filter-bytecode.h
+ *
+ * LTTng filter bytecode
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/macros.h>
+
+#include "filter-ast.h"
+
+/*
+ * offsets are absolute from start of bytecode.
+ */
+
+struct field_ref {
+       /* Initially, symbol offset. After link, field offset. */
+       uint16_t offset;
+} LTTNG_PACKED;
+
+struct get_symbol {
+       /* Symbol offset. */
+       uint16_t offset;
+} LTTNG_PACKED;
+
+struct get_index_u16 {
+       uint16_t index;
+} LTTNG_PACKED;
+
+struct get_index_u64 {
+       uint64_t index;
+} LTTNG_PACKED;
+
+struct literal_numeric {
+       int64_t v;
+} LTTNG_PACKED;
+
+struct literal_double {
+       double v;
+} LTTNG_PACKED;
+
+struct literal_string {
+       char string[0];
+} LTTNG_PACKED;
+
+enum filter_op {
+       FILTER_OP_UNKNOWN                       = 0,
+
+       FILTER_OP_RETURN                        = 1,
+
+       /* binary */
+       FILTER_OP_MUL                           = 2,
+       FILTER_OP_DIV                           = 3,
+       FILTER_OP_MOD                           = 4,
+       FILTER_OP_PLUS                          = 5,
+       FILTER_OP_MINUS                         = 6,
+       FILTER_OP_BIT_RSHIFT                    = 7,
+       FILTER_OP_BIT_LSHIFT                    = 8,
+       FILTER_OP_BIT_AND                       = 9,
+       FILTER_OP_BIT_OR                        = 10,
+       FILTER_OP_BIT_XOR                       = 11,
+
+       /* binary comparators */
+       FILTER_OP_EQ                            = 12,
+       FILTER_OP_NE                            = 13,
+       FILTER_OP_GT                            = 14,
+       FILTER_OP_LT                            = 15,
+       FILTER_OP_GE                            = 16,
+       FILTER_OP_LE                            = 17,
+
+       /* string binary comparator: apply to  */
+       FILTER_OP_EQ_STRING                     = 18,
+       FILTER_OP_NE_STRING                     = 19,
+       FILTER_OP_GT_STRING                     = 20,
+       FILTER_OP_LT_STRING                     = 21,
+       FILTER_OP_GE_STRING                     = 22,
+       FILTER_OP_LE_STRING                     = 23,
+
+       /* s64 binary comparator */
+       FILTER_OP_EQ_S64                        = 24,
+       FILTER_OP_NE_S64                        = 25,
+       FILTER_OP_GT_S64                        = 26,
+       FILTER_OP_LT_S64                        = 27,
+       FILTER_OP_GE_S64                        = 28,
+       FILTER_OP_LE_S64                        = 29,
+
+       /* double binary comparator */
+       FILTER_OP_EQ_DOUBLE                     = 30,
+       FILTER_OP_NE_DOUBLE                     = 31,
+       FILTER_OP_GT_DOUBLE                     = 32,
+       FILTER_OP_LT_DOUBLE                     = 33,
+       FILTER_OP_GE_DOUBLE                     = 34,
+       FILTER_OP_LE_DOUBLE                     = 35,
+
+       /* Mixed S64-double binary comparators */
+       FILTER_OP_EQ_DOUBLE_S64                 = 36,
+       FILTER_OP_NE_DOUBLE_S64                 = 37,
+       FILTER_OP_GT_DOUBLE_S64                 = 38,
+       FILTER_OP_LT_DOUBLE_S64                 = 39,
+       FILTER_OP_GE_DOUBLE_S64                 = 40,
+       FILTER_OP_LE_DOUBLE_S64                 = 41,
+
+       FILTER_OP_EQ_S64_DOUBLE                 = 42,
+       FILTER_OP_NE_S64_DOUBLE                 = 43,
+       FILTER_OP_GT_S64_DOUBLE                 = 44,
+       FILTER_OP_LT_S64_DOUBLE                 = 45,
+       FILTER_OP_GE_S64_DOUBLE                 = 46,
+       FILTER_OP_LE_S64_DOUBLE                 = 47,
+
+       /* unary */
+       FILTER_OP_UNARY_PLUS                    = 48,
+       FILTER_OP_UNARY_MINUS                   = 49,
+       FILTER_OP_UNARY_NOT                     = 50,
+       FILTER_OP_UNARY_PLUS_S64                = 51,
+       FILTER_OP_UNARY_MINUS_S64               = 52,
+       FILTER_OP_UNARY_NOT_S64                 = 53,
+       FILTER_OP_UNARY_PLUS_DOUBLE             = 54,
+       FILTER_OP_UNARY_MINUS_DOUBLE            = 55,
+       FILTER_OP_UNARY_NOT_DOUBLE              = 56,
+
+       /* logical */
+       FILTER_OP_AND                           = 57,
+       FILTER_OP_OR                            = 58,
+
+       /* load field ref */
+       FILTER_OP_LOAD_FIELD_REF                = 59,
+       FILTER_OP_LOAD_FIELD_REF_STRING         = 60,
+       FILTER_OP_LOAD_FIELD_REF_SEQUENCE       = 61,
+       FILTER_OP_LOAD_FIELD_REF_S64            = 62,
+       FILTER_OP_LOAD_FIELD_REF_DOUBLE         = 63,
+
+       /* load immediate from operand */
+       FILTER_OP_LOAD_STRING                   = 64,
+       FILTER_OP_LOAD_S64                      = 65,
+       FILTER_OP_LOAD_DOUBLE                   = 66,
+
+       /* cast */
+       FILTER_OP_CAST_TO_S64                   = 67,
+       FILTER_OP_CAST_DOUBLE_TO_S64            = 68,
+       FILTER_OP_CAST_NOP                      = 69,
+
+       /* get context ref */
+       FILTER_OP_GET_CONTEXT_REF               = 70,
+       FILTER_OP_GET_CONTEXT_REF_STRING        = 71,
+       FILTER_OP_GET_CONTEXT_REF_S64           = 72,
+       FILTER_OP_GET_CONTEXT_REF_DOUBLE        = 73,
+
+       /* load userspace field ref */
+       FILTER_OP_LOAD_FIELD_REF_USER_STRING    = 74,
+       FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE  = 75,
+
+       /*
+        * load immediate star globbing pattern (literal string)
+        * from immediate
+        */
+       FILTER_OP_LOAD_STAR_GLOB_STRING         = 76,
+
+       /* globbing pattern binary operator: apply to */
+       FILTER_OP_EQ_STAR_GLOB_STRING           = 77,
+       FILTER_OP_NE_STAR_GLOB_STRING           = 78,
+
+       /*
+        * Instructions for recursive traversal through composed types.
+        */
+       FILTER_OP_GET_CONTEXT_ROOT              = 79,
+       FILTER_OP_GET_APP_CONTEXT_ROOT          = 80,
+       FILTER_OP_GET_PAYLOAD_ROOT              = 81,
+
+       FILTER_OP_GET_SYMBOL                    = 82,
+       FILTER_OP_GET_SYMBOL_FIELD              = 83,
+       FILTER_OP_GET_INDEX_U16                 = 84,
+       FILTER_OP_GET_INDEX_U64                 = 85,
+
+       FILTER_OP_LOAD_FIELD                    = 86,
+       FILTER_OP_LOAD_FIELD_S8                 = 87,
+       FILTER_OP_LOAD_FIELD_S16                = 88,
+       FILTER_OP_LOAD_FIELD_S32                = 89,
+       FILTER_OP_LOAD_FIELD_S64                = 90,
+       FILTER_OP_LOAD_FIELD_U8                 = 91,
+       FILTER_OP_LOAD_FIELD_U16                = 92,
+       FILTER_OP_LOAD_FIELD_U32                = 93,
+       FILTER_OP_LOAD_FIELD_U64                = 94,
+       FILTER_OP_LOAD_FIELD_STRING             = 95,
+       FILTER_OP_LOAD_FIELD_SEQUENCE           = 96,
+       FILTER_OP_LOAD_FIELD_DOUBLE             = 97,
+
+       FILTER_OP_UNARY_BIT_NOT                 = 98,
+
+       FILTER_OP_RETURN_S64                    = 99,
+
+       NR_FILTER_OPS,
+};
+
+typedef uint8_t filter_opcode_t;
+
+struct load_op {
+       filter_opcode_t op;
+       char data[0];
+       /* data to load. Size known by enum filter_opcode and null-term char. */
+} LTTNG_PACKED;
+
+struct binary_op {
+       filter_opcode_t op;
+} LTTNG_PACKED;
+
+struct unary_op {
+       filter_opcode_t op;
+} LTTNG_PACKED;
+
+/* skip_offset is absolute from start of bytecode */
+struct logical_op {
+       filter_opcode_t op;
+       uint16_t skip_offset;   /* bytecode insn, if skip second test */
+} LTTNG_PACKED;
+
+struct cast_op {
+       filter_opcode_t op;
+} LTTNG_PACKED;
+
+struct return_op {
+       filter_opcode_t op;
+} LTTNG_PACKED;
+
+struct lttng_filter_bytecode_alloc {
+       uint32_t alloc_len;
+       struct lttng_filter_bytecode b;
+};
+
+static inline
+unsigned int bytecode_get_len(struct lttng_filter_bytecode *bytecode)
+{
+       return bytecode->len;
+}
+
+#endif /* _FILTER_BYTECODE_H */
diff --git a/src/common/filter/filter-grammar-test.c b/src/common/filter/filter-grammar-test.c
new file mode 100644 (file)
index 0000000..70656e1
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * filter-grammar-test.c
+ *
+ * LTTng filter grammar test
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include "filter-ast.h"
+#include "filter-parser.h"
+#include "filter-bytecode.h"
+
+int main(int argc, char **argv)
+{
+       struct filter_parser_ctx *ctx;
+       int ret;
+       int print_xml = 0, generate_ir = 0, generate_bytecode = 0,
+               print_bytecode = 0;
+       int i;
+
+       for (i = 1; i < argc; i++) {
+               if (strcmp(argv[i], "-p") == 0)
+                       print_xml = 1;
+               else if (strcmp(argv[i], "-i") == 0)
+                       generate_ir = 1;
+               else if (strcmp(argv[i], "-b") == 0)
+                       generate_bytecode = 1;
+               else if (strcmp(argv[i], "-d") == 0)
+                       filter_parser_debug = 1;
+               else if (strcmp(argv[i], "-B") == 0)
+                       print_bytecode = 1;
+       }
+
+       /*
+        * Force generate the bytecode if the user asks to print the bytecode
+        * (can't print it without generating it first).
+        */
+       if (print_bytecode) {
+               generate_bytecode = 1;
+       }
+
+       /*
+        * Force generate the IR if the user asks to generate the bytecode
+        * (the bytecode is generated by visiting the IR).
+        */
+       if (generate_bytecode) {
+               generate_ir = 1;
+       }
+
+       ctx = filter_parser_ctx_alloc(stdin);
+       if (!ctx) {
+               fprintf(stderr, "Error allocating parser\n");
+               goto alloc_error;
+       }
+       ret = filter_parser_ctx_append_ast(ctx);
+       if (ret) {
+               fprintf(stderr, "Parse error\n");
+               goto parse_error;
+       }
+       if (print_xml) {
+               ret = filter_visitor_print_xml(ctx, stdout, 0);
+               if (ret) {
+                       fflush(stdout);
+                       fprintf(stderr, "XML print error\n");
+                       goto parse_error;
+               }
+       }
+       if (generate_ir) {
+               printf("Generating IR... ");
+               fflush(stdout);
+               ret = filter_visitor_ir_generate(ctx);
+               if (ret) {
+                       fprintf(stderr, "Generate IR error\n");
+                       goto parse_error;
+               }
+               printf("done\n");
+
+               printf("Validating IR... ");
+               fflush(stdout);
+               ret = filter_visitor_ir_check_binary_op_nesting(ctx);
+               if (ret) {
+                       goto parse_error;
+               }
+               printf("done\n");
+       }
+       if (generate_bytecode) {
+               printf("Generating bytecode... ");
+               fflush(stdout);
+               ret = filter_visitor_bytecode_generate(ctx);
+               if (ret) {
+                       fprintf(stderr, "Generate bytecode error\n");
+                       goto parse_error;
+               }
+               printf("done\n");
+               printf("Size of bytecode generated: %u bytes.\n",
+                       bytecode_get_len(&ctx->bytecode->b));
+       }
+
+       if (print_bytecode) {
+               unsigned int bytecode_len, len, i;
+
+               len = bytecode_get_len(&ctx->bytecode->b);
+               bytecode_len = ctx->bytecode->b.reloc_table_offset;
+               printf("Bytecode:\n");
+               for (i = 0; i < bytecode_len; i++) {
+                       printf("0x%X ",
+                               ((uint8_t *) ctx->bytecode->b.data)[i]);
+               }
+               printf("\n");
+               printf("Reloc table:\n");
+               for (i = bytecode_len; i < len;) {
+                       printf("{ 0x%X, ",
+                               *(uint16_t *) &ctx->bytecode->b.data[i]);
+                       i += sizeof(uint16_t);
+                       printf("%s } ", &((char *) ctx->bytecode->b.data)[i]);
+                       i += strlen(&((char *) ctx->bytecode->b.data)[i]) + 1;
+               }
+               printf("\n");
+       }
+
+       filter_bytecode_free(ctx);
+       filter_ir_free(ctx);
+       filter_parser_ctx_free(ctx);
+       return 0;
+
+parse_error:
+       filter_bytecode_free(ctx);
+       filter_ir_free(ctx);
+       filter_parser_ctx_free(ctx);
+alloc_error:
+       exit(EXIT_FAILURE);
+}
diff --git a/src/common/filter/filter-ir.h b/src/common/filter/filter-ir.h
new file mode 100644 (file)
index 0000000..d62c0ee
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef _FILTER_IR_H
+#define _FILTER_IR_H
+
+/*
+ * filter-ir.h
+ *
+ * LTTng filter ir
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include "filter-ast.h"
+
+enum ir_op_signedness {
+       IR_SIGN_UNKNOWN = 0,
+       IR_SIGNED,
+       IR_UNSIGNED,
+       IR_SIGN_DYN,            /* signedness determined dynamically */
+};
+
+enum ir_data_type {
+       IR_DATA_UNKNOWN = 0,
+       IR_DATA_STRING,
+       IR_DATA_NUMERIC,        /* numeric and boolean */
+       IR_DATA_FLOAT,
+       IR_DATA_FIELD_REF,
+       IR_DATA_GET_CONTEXT_REF,
+       IR_DATA_EXPRESSION,
+};
+
+enum ir_op_type {
+       IR_OP_UNKNOWN = 0,
+       IR_OP_ROOT,
+       IR_OP_LOAD,
+       IR_OP_UNARY,
+       IR_OP_BINARY,
+       IR_OP_LOGICAL,
+};
+
+/* left or right child */
+enum ir_side {
+       IR_SIDE_UNKNOWN = 0,
+       IR_LEFT,
+       IR_RIGHT,
+};
+
+enum ir_load_string_type {
+       /* Plain, no globbing at all: `hello world`. */
+       IR_LOAD_STRING_TYPE_PLAIN = 0,
+
+       /* Star at the end only: `hello *`. */
+       IR_LOAD_STRING_TYPE_GLOB_STAR_END,
+
+       /* At least one star, anywhere, but not at the end only: `he*wor*`. */
+       IR_LOAD_STRING_TYPE_GLOB_STAR,
+};
+
+struct ir_op_root {
+       struct ir_op *child;
+};
+
+enum ir_load_expression_type {
+       IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT,
+       IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT,
+       IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT,
+       IR_LOAD_EXPRESSION_GET_SYMBOL,
+       IR_LOAD_EXPRESSION_GET_INDEX,
+       IR_LOAD_EXPRESSION_LOAD_FIELD,
+};
+
+struct ir_load_expression_op {
+       struct ir_load_expression_op *next;
+       enum ir_load_expression_type type;
+       union {
+               char *symbol;
+               uint64_t index;
+       } u;
+};
+
+struct ir_load_expression {
+       struct ir_load_expression_op *child;
+};
+
+struct ir_op_load {
+       union {
+               struct {
+                       enum ir_load_string_type type;
+                       char *value;
+               } string;
+               int64_t num;
+               double flt;
+               char *ref;
+               struct ir_load_expression *expression;
+       } u;
+};
+
+struct ir_op_unary {
+       enum unary_op_type type;
+       struct ir_op *child;
+};
+
+struct ir_op_binary {
+       enum op_type type;
+       struct ir_op *left;
+       struct ir_op *right;
+};
+
+struct ir_op_logical {
+       enum op_type type;
+       struct ir_op *left;
+       struct ir_op *right;
+};
+
+struct ir_op {
+       /* common to all ops */
+       enum ir_op_type op;
+       enum ir_data_type data_type;
+       enum ir_op_signedness signedness;
+       enum ir_side side;
+
+       union {
+               struct ir_op_root root;
+               struct ir_op_load load;
+               struct ir_op_unary unary;
+               struct ir_op_binary binary;
+               struct ir_op_logical logical;
+       } u;
+};
+
+#endif /* _FILTER_IR_H */
diff --git a/src/common/filter/filter-lexer.l b/src/common/filter/filter-lexer.l
new file mode 100644 (file)
index 0000000..cdb099a
--- /dev/null
@@ -0,0 +1,129 @@
+%{
+/*
+ * filter-lexer.l
+ *
+ * LTTng filter lexer
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include "filter-ast.h"
+#include "filter-parser.h"
+
+static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
+       __attribute__((unused));
+static int input (yyscan_t yyscanner) __attribute__((unused));
+
+%}
+
+%x comment_ml comment_sl string_lit char_const
+%option reentrant yylineno noyywrap bison-bridge
+%option extra-type="struct filter_parser_ctx *"
+       /* bison-locations */
+
+D                              [0-9]
+L                              [a-zA-Z_]
+H                              [a-fA-F0-9]
+E                              ([Ee][+-]?{D}+)
+P                              ([Pp][+-]?{D}+)
+FS                             (f|F|l|L)
+IS                             ((u|U)|(u|U)?(l|L|ll|LL)|(l|L|ll|LL)(u|U))
+
+INTEGER_SUFFIX                 [ \n\t]*(U|UL|ULL|LU|LLU|Ul|Ull|lU|llU|u|uL|uLL|Lu|LLu|ul|ull|lu|llu)
+DIGIT                          [0-9]
+NONDIGIT                       [a-zA-Z_]
+HEXDIGIT                       [0-9A-Fa-f]
+OCTALDIGIT                     [0-7]
+UCHARLOWERCASE                 \\u{HEXDIGIT}{4}
+UCHARUPPERCASE                 \\U{HEXDIGIT}{8}
+ID_EXTRA_CHAR                  (":")
+ID_NONDIGIT                    {NONDIGIT}|{UCHARLOWERCASE}|{UCHARUPPERCASE}|{ID_EXTRA_CHAR}
+IDENTIFIER                     {ID_NONDIGIT}({ID_NONDIGIT}|{DIGIT})*
+ESCSEQ                         \\(\'|\"|\?|\\|a|b|f|n|r|t|v|{OCTALDIGIT}{1,3}|u{HEXDIGIT}{4}|U{HEXDIGIT}{8}|x{HEXDIGIT}+)
+%%
+
+                               /*
+                                * Using start conditions to deal with comments
+                                * and strings.
+                                */ 
+
+"/*"                           BEGIN(comment_ml);
+<comment_ml>[^*\n]*            /* eat anything that's not a '*' */
+<comment_ml>"*"+[^*/\n]*       /* eat up '*'s not followed by '/'s */
+<comment_ml>\n                 ++yylineno;
+<comment_ml>"*"+"/"            BEGIN(INITIAL);
+
+"//"                           BEGIN(comment_sl);
+<comment_sl>[^\n]*\n           ++yylineno; BEGIN(INITIAL);
+
+L\'                            BEGIN(char_const); return CHARACTER_CONSTANT_START;
+\'                             BEGIN(char_const); return CHARACTER_CONSTANT_START;
+<char_const>\'                 BEGIN(INITIAL); return SQUOTE;
+
+L\"                            BEGIN(string_lit); return STRING_LITERAL_START;
+\"                             BEGIN(string_lit); return STRING_LITERAL_START;
+<string_lit>\"                 BEGIN(INITIAL); return DQUOTE;
+
+<char_const,string_lit>ESCSEQ  return ESCSEQ;
+<char_const,string_lit>\n      ; /* ignore */
+<char_const,string_lit>.       setstring(yyextra, yylval, yytext); return CHAR_STRING_TOKEN;
+
+
+0[xX]{H}+{IS}?                 setstring(yyextra, yylval, yytext); return HEXADECIMAL_CONSTANT;
+0[0-7]*{IS}?                   setstring(yyextra, yylval, yytext); return OCTAL_CONSTANT;
+[1-9]{D}*{IS}?                 setstring(yyextra, yylval, yytext); return DECIMAL_CONSTANT;
+
+{D}+{E}{FS}?                   setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
+{D}*"."{D}+{E}?{FS}?           setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
+{D}+"."{D}*{E}?{FS}?           setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
+0[xX]{H}+{P}{FS}?              setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
+0[xX]{H}*"."{H}+{P}?{FS}?      setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
+0[xX]{H}+"."{H}*{P}?{FS}?      setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
+
+"["                            return LSBRAC;
+"]"                            return RSBRAC;
+"("                            return LPAREN;
+")"                            return RPAREN;
+"{"                            return LBRAC;
+"}"                            return RBRAC;
+"->"                           return RARROW;
+
+"*"                            return STAR;
+"+"                            return PLUS;
+"-"                            return MINUS;
+
+"%"                            return MOD_OP;
+"/"                            return DIV_OP;
+">>"                           return RIGHT_OP;
+"<<"                           return LEFT_OP;
+
+"=="                           return EQ_OP;
+"!="                           return NE_OP;
+"<="                           return LE_OP;
+">="                           return GE_OP;
+"<"                            return LT_OP;
+">"                            return GT_OP;
+"&&"                           return AND_OP;
+"||"                           return OR_OP;
+"!"                            return NOT_OP;
+
+":="                           return ASSIGN;
+":"                            return COLON;
+";"                            return SEMICOLON;
+"..."                          return DOTDOTDOT;
+"."                            return DOT;
+"="                            return EQUAL;
+","                            return COMMA;
+"^"                            return XOR_BIN;
+"&"                            return AND_BIN;
+"|"                            return OR_BIN;
+"~"                            return NOT_BIN;
+"$"{IDENTIFIER}                        printf_debug("<GLOBAL_IDENTIFIER %s>\n", yytext); setstring(yyextra, yylval, yytext); return GLOBAL_IDENTIFIER;
+{IDENTIFIER}                   printf_debug("<IDENTIFIER %s>\n", yytext); setstring(yyextra, yylval, yytext); return IDENTIFIER;
+[ \t\n]+                       ; /* ignore */
+.                              return ERROR;
+%%
diff --git a/src/common/filter/filter-parser.y b/src/common/filter/filter-parser.y
new file mode 100644 (file)
index 0000000..245d83c
--- /dev/null
@@ -0,0 +1,812 @@
+%{
+/*
+ * filter-parser.y
+ *
+ * LTTng filter expression parser
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Grammar inspired from http://www.quut.com/c/ANSI-C-grammar-y.html
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include "filter-ast.h"
+#include "filter-parser.h"
+#include "filter-bytecode.h"
+#include "memstream.h"
+
+#include <common/macros.h>
+
+#define WIDTH_u64_SCANF_IS_A_BROKEN_API        "20"
+#define WIDTH_o64_SCANF_IS_A_BROKEN_API        "22"
+#define WIDTH_x64_SCANF_IS_A_BROKEN_API        "17"
+#define WIDTH_lg_SCANF_IS_A_BROKEN_API "4096"  /* Hugely optimistic approximation */
+
+#ifdef DEBUG
+static const int print_xml = 1;
+#define dbg_printf(fmt, args...)       \
+       printf("[debug filter_parser] " fmt, ## args)
+#else
+static const int print_xml = 0;
+#define dbg_printf(fmt, args...)                               \
+do {                                                           \
+       /* do nothing but check printf format */                \
+       if (0)                                                  \
+               printf("[debug filter_parser] " fmt, ## args);  \
+} while (0)
+#endif
+
+LTTNG_HIDDEN
+int yydebug;
+LTTNG_HIDDEN
+int filter_parser_debug = 0;
+
+LTTNG_HIDDEN
+int yyparse(struct filter_parser_ctx *parser_ctx, yyscan_t scanner);
+LTTNG_HIDDEN
+int yylex(union YYSTYPE *yyval, yyscan_t scanner);
+LTTNG_HIDDEN
+int yylex_init_extra(struct filter_parser_ctx *parser_ctx, yyscan_t * ptr_yy_globals);
+LTTNG_HIDDEN
+int yylex_destroy(yyscan_t yyparser_ctx);
+LTTNG_HIDDEN
+void yyrestart(FILE * in_str, yyscan_t parser_ctx);
+
+struct gc_string {
+       struct cds_list_head gc;
+       size_t alloclen;
+       char s[];
+};
+
+static const char *node_type_to_str[] = {
+       [ NODE_UNKNOWN ] = "NODE_UNKNOWN",
+       [ NODE_ROOT ] = "NODE_ROOT",
+       [ NODE_EXPRESSION ] = "NODE_EXPRESSION",
+       [ NODE_OP ] = "NODE_OP",
+       [ NODE_UNARY_OP ] = "NODE_UNARY_OP",
+};
+
+LTTNG_HIDDEN
+const char *node_type(struct filter_node *node)
+{
+       if (node->type < NR_NODE_TYPES)
+               return node_type_to_str[node->type];
+       else
+               return NULL;
+}
+
+static struct gc_string *gc_string_alloc(struct filter_parser_ctx *parser_ctx,
+                                        size_t len)
+{
+       struct gc_string *gstr;
+       size_t alloclen;
+
+       /* TODO: could be faster with find first bit or glib Gstring */
+       /* sizeof long to account for malloc header (int or long ?) */
+       for (alloclen = 8; alloclen < sizeof(long) + sizeof(*gstr) + len;
+            alloclen *= 2);
+
+       gstr = zmalloc(alloclen);
+       if (!gstr) {
+               goto end;
+       }
+       cds_list_add(&gstr->gc, &parser_ctx->allocated_strings);
+       gstr->alloclen = alloclen;
+end:
+       return gstr;
+}
+
+/*
+ * note: never use gc_string_append on a string that has external references.
+ * gsrc will be garbage collected immediately, and gstr might be.
+ * Should only be used to append characters to a string literal or constant.
+ */
+static
+struct gc_string *gc_string_append(struct filter_parser_ctx *parser_ctx,
+                                  struct gc_string *gstr,
+                                  struct gc_string *gsrc)
+{
+       size_t newlen = strlen(gsrc->s) + strlen(gstr->s) + 1;
+       size_t alloclen;
+
+       /* TODO: could be faster with find first bit or glib Gstring */
+       /* sizeof long to account for malloc header (int or long ?) */
+       for (alloclen = 8; alloclen < sizeof(long) + sizeof(*gstr) + newlen;
+            alloclen *= 2);
+
+       if (alloclen > gstr->alloclen) {
+               struct gc_string *newgstr;
+
+               newgstr = gc_string_alloc(parser_ctx, newlen);
+               strcpy(newgstr->s, gstr->s);
+               strcat(newgstr->s, gsrc->s);
+               cds_list_del(&gstr->gc);
+               free(gstr);
+               gstr = newgstr;
+       } else {
+               strcat(gstr->s, gsrc->s);
+       }
+       cds_list_del(&gsrc->gc);
+       free(gsrc);
+       return gstr;
+}
+
+LTTNG_HIDDEN
+void setstring(struct filter_parser_ctx *parser_ctx, YYSTYPE *lvalp, const char *src)
+{
+       lvalp->gs = gc_string_alloc(parser_ctx, strlen(src) + 1);
+       strcpy(lvalp->gs->s, src);
+}
+
+static struct filter_node *make_node(struct filter_parser_ctx *scanner,
+                                 enum node_type type)
+{
+       struct filter_ast *ast = filter_parser_get_ast(scanner);
+       struct filter_node *node;
+
+       node = zmalloc(sizeof(*node));
+       if (!node)
+               return NULL;
+       memset(node, 0, sizeof(*node));
+       node->type = type;
+       cds_list_add(&node->gc, &ast->allocated_nodes);
+
+       switch (type) {
+       case NODE_ROOT:
+               fprintf(stderr, "[error] %s: trying to create root node\n", __func__);
+               break;
+
+       case NODE_EXPRESSION:
+               break;
+       case NODE_OP:
+               break;
+       case NODE_UNARY_OP:
+               break;
+
+       case NODE_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown node type %d\n", __func__,
+                       (int) type);
+               break;
+       }
+
+       return node;
+}
+
+static struct filter_node *make_op_node(struct filter_parser_ctx *scanner,
+                       enum op_type type,
+                       struct filter_node *lchild,
+                       struct filter_node *rchild)
+{
+       struct filter_ast *ast = filter_parser_get_ast(scanner);
+       struct filter_node *node;
+
+       node = zmalloc(sizeof(*node));
+       if (!node)
+               return NULL;
+       memset(node, 0, sizeof(*node));
+       node->type = NODE_OP;
+       cds_list_add(&node->gc, &ast->allocated_nodes);
+       node->u.op.type = type;
+       node->u.op.lchild = lchild;
+       node->u.op.rchild = rchild;
+       return node;
+}
+
+static
+void yyerror(struct filter_parser_ctx *parser_ctx, yyscan_t scanner, const char *str)
+{
+       fprintf(stderr, "error %s\n", str);
+}
+
+#define parse_error(parser_ctx, str)                           \
+do {                                                           \
+       yyerror(parser_ctx, parser_ctx->scanner, YY_("parse error: " str "\n"));        \
+       YYERROR;                                                \
+} while (0)
+
+static void free_strings(struct cds_list_head *list)
+{
+       struct gc_string *gstr, *tmp;
+
+       cds_list_for_each_entry_safe(gstr, tmp, list, gc)
+               free(gstr);
+}
+
+static struct filter_ast *filter_ast_alloc(void)
+{
+       struct filter_ast *ast;
+
+       ast = zmalloc(sizeof(*ast));
+       if (!ast)
+               return NULL;
+       memset(ast, 0, sizeof(*ast));
+       CDS_INIT_LIST_HEAD(&ast->allocated_nodes);
+       ast->root.type = NODE_ROOT;
+       return ast;
+}
+
+static void filter_ast_free(struct filter_ast *ast)
+{
+       struct filter_node *node, *tmp;
+
+       cds_list_for_each_entry_safe(node, tmp, &ast->allocated_nodes, gc)
+               free(node);
+       free(ast);
+}
+
+LTTNG_HIDDEN
+int filter_parser_ctx_append_ast(struct filter_parser_ctx *parser_ctx)
+{
+       return yyparse(parser_ctx, parser_ctx->scanner);
+}
+
+LTTNG_HIDDEN
+struct filter_parser_ctx *filter_parser_ctx_alloc(FILE *input)
+{
+       struct filter_parser_ctx *parser_ctx;
+       int ret;
+
+       yydebug = filter_parser_debug;
+
+       parser_ctx = zmalloc(sizeof(*parser_ctx));
+       if (!parser_ctx)
+               return NULL;
+       memset(parser_ctx, 0, sizeof(*parser_ctx));
+
+       ret = yylex_init_extra(parser_ctx, &parser_ctx->scanner);
+       if (ret) {
+               fprintf(stderr, "yylex_init error\n");
+               goto cleanup_parser_ctx;
+       }
+       /* Start processing new stream */
+       yyrestart(input, parser_ctx->scanner);
+
+       parser_ctx->ast = filter_ast_alloc();
+       if (!parser_ctx->ast)
+               goto cleanup_lexer;
+       CDS_INIT_LIST_HEAD(&parser_ctx->allocated_strings);
+
+       if (yydebug)
+               fprintf(stdout, "parser_ctx input is a%s.\n",
+                       isatty(fileno(input)) ? "n interactive tty" :
+                                               " noninteractive file");
+
+       return parser_ctx;
+
+cleanup_lexer:
+       ret = yylex_destroy(parser_ctx->scanner);
+       if (!ret)
+               fprintf(stderr, "yylex_destroy error\n");
+cleanup_parser_ctx:
+       free(parser_ctx);
+       return NULL;
+}
+
+LTTNG_HIDDEN
+void filter_parser_ctx_free(struct filter_parser_ctx *parser_ctx)
+{
+       int ret;
+
+       free_strings(&parser_ctx->allocated_strings);
+       filter_ast_free(parser_ctx->ast);
+       ret = yylex_destroy(parser_ctx->scanner);
+       if (ret)
+               fprintf(stderr, "yylex_destroy error\n");
+       free(parser_ctx);
+}
+
+LTTNG_HIDDEN
+int filter_parser_ctx_create_from_filter_expression(
+               const char *filter_expression, struct filter_parser_ctx **ctxp)
+{
+       int ret;
+       struct filter_parser_ctx *ctx = NULL;
+       FILE *fmem = NULL;
+
+       assert(filter_expression);
+       assert(ctxp);
+
+       /*
+        * Casting const to non-const, as the underlying function will use it in
+        * read-only mode.
+        */
+       fmem = lttng_fmemopen((void *) filter_expression,
+                       strlen(filter_expression), "r");
+       if (!fmem) {
+               fprintf(stderr, "Error opening memory as stream\n");
+               ret = -LTTNG_ERR_FILTER_NOMEM;
+               goto error;
+       }
+       ctx = filter_parser_ctx_alloc(fmem);
+       if (!ctx) {
+               fprintf(stderr, "Error allocating parser\n");
+               ret = -LTTNG_ERR_FILTER_NOMEM;
+               goto filter_alloc_error;
+       }
+       ret = filter_parser_ctx_append_ast(ctx);
+       if (ret) {
+               fprintf(stderr, "Parse error\n");
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+       if (print_xml) {
+               ret = filter_visitor_print_xml(ctx, stdout, 0);
+               if (ret) {
+                       fflush(stdout);
+                       fprintf(stderr, "XML print error\n");
+                       ret = -LTTNG_ERR_FILTER_INVAL;
+                       goto parse_error;
+               }
+       }
+
+       dbg_printf("Generating IR... ");
+       fflush(stdout);
+       ret = filter_visitor_ir_generate(ctx);
+       if (ret) {
+               fprintf(stderr, "Generate IR error\n");
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+       dbg_printf("done\n");
+
+       dbg_printf("Validating IR... ");
+       fflush(stdout);
+       ret = filter_visitor_ir_check_binary_op_nesting(ctx);
+       if (ret) {
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+
+       /* Normalize globbing patterns in the expression. */
+       ret = filter_visitor_ir_normalize_glob_patterns(ctx);
+       if (ret) {
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+
+       /* Validate strings used as literals in the expression. */
+       ret = filter_visitor_ir_validate_string(ctx);
+       if (ret) {
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+
+       /* Validate globbing patterns in the expression. */
+       ret = filter_visitor_ir_validate_globbing(ctx);
+       if (ret) {
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+
+       dbg_printf("done\n");
+
+       dbg_printf("Generating bytecode... ");
+       fflush(stdout);
+       ret = filter_visitor_bytecode_generate(ctx);
+       if (ret) {
+               fprintf(stderr, "Generate bytecode error\n");
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+       dbg_printf("done\n");
+       dbg_printf("Size of bytecode generated: %u bytes.\n",
+                       bytecode_get_len(&ctx->bytecode->b));
+
+       /* No need to keep the memory stream. */
+       if (fclose(fmem) != 0) {
+               fprintf(stderr, "fclose (%d) \n", errno);
+               ret = -LTTNG_ERR_FILTER_INVAL;
+       }
+
+       *ctxp = ctx;
+       return 0;
+
+parse_error:
+       filter_ir_free(ctx);
+       filter_parser_ctx_free(ctx);
+filter_alloc_error:
+       if (fclose(fmem) != 0) {
+               fprintf(stderr, "fclose (%d) \n", errno);
+       }
+error:
+       return ret;
+}
+
+%}
+
+%code provides
+{
+#include "common/macros.h"
+
+LTTNG_HIDDEN
+void setstring(struct filter_parser_ctx *parser_ctx, YYSTYPE *lvalp, const char *src);
+}
+
+%define api.pure
+       /* %locations */
+%parse-param {struct filter_parser_ctx *parser_ctx}
+%parse-param {yyscan_t scanner}
+%lex-param {yyscan_t scanner}
+%start translation_unit
+%token CHARACTER_CONSTANT_START SQUOTE STRING_LITERAL_START DQUOTE
+%token ESCSEQ CHAR_STRING_TOKEN
+%token DECIMAL_CONSTANT OCTAL_CONSTANT HEXADECIMAL_CONSTANT FLOAT_CONSTANT
+%token LSBRAC RSBRAC LPAREN RPAREN LBRAC RBRAC RARROW
+%token STAR PLUS MINUS
+%token MOD_OP DIV_OP RIGHT_OP LEFT_OP
+%token EQ_OP NE_OP LE_OP GE_OP LT_OP GT_OP AND_OP OR_OP NOT_OP
+%token ASSIGN COLON SEMICOLON DOTDOTDOT DOT EQUAL COMMA
+%token XOR_BIN AND_BIN OR_BIN NOT_BIN
+
+%token <gs> IDENTIFIER GLOBAL_IDENTIFIER
+%token ERROR
+%union
+{
+       long long ll;
+       char c;
+       struct gc_string *gs;
+       struct filter_node *n;
+}
+
+%type <gs> s_char s_char_sequence c_char c_char_sequence
+
+%type <n> primary_expression
+%type <n> prefix_expression
+%type <n> prefix_expression_rec
+%type <n> postfix_expression
+%type <n> unary_expression
+%type <n> unary_operator
+%type <n> multiplicative_expression
+%type <n> additive_expression
+%type <n> shift_expression
+%type <n> relational_expression
+%type <n> equality_expression
+%type <n> and_expression
+%type <n> exclusive_or_expression
+%type <n> inclusive_or_expression
+%type <n> logical_and_expression
+%type <n> logical_or_expression
+%type <n> expression
+%type <n> identifiers
+
+%%
+
+
+/* 1.5 Constants */
+
+c_char_sequence:
+               c_char
+               {       $$ = $1;                                        }
+       |       c_char_sequence c_char
+               {       $$ = gc_string_append(parser_ctx, $1, $2);              }
+       ;
+
+c_char:
+               CHAR_STRING_TOKEN
+               {       $$ = yylval.gs;                                 }
+       |       ESCSEQ
+               {
+                       parse_error(parser_ctx, "escape sequences not supported yet");
+               }
+       ;
+
+/* 1.6 String literals */
+
+s_char_sequence:
+               s_char
+               {       $$ = $1;                                        }
+       |       s_char_sequence s_char
+               {       $$ = gc_string_append(parser_ctx, $1, $2);              }
+       ;
+
+s_char:
+               CHAR_STRING_TOKEN
+               {       $$ = yylval.gs;                                 }
+       |       ESCSEQ
+               {
+                       parse_error(parser_ctx, "escape sequences not supported yet");
+               }
+       ;
+
+primary_expression:
+               DECIMAL_CONSTANT
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_CONSTANT;
+                       if (sscanf(yylval.gs->s, "%" WIDTH_u64_SCANF_IS_A_BROKEN_API SCNu64,
+                                       &$$->u.expression.u.constant) != 1) {
+                               parse_error(parser_ctx, "cannot scanf decimal constant");
+                       }
+               }
+       |       OCTAL_CONSTANT
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_CONSTANT;
+                       if (!strcmp(yylval.gs->s, "0")) {
+                               $$->u.expression.u.constant = 0;
+                       } else if (sscanf(yylval.gs->s, "0%" WIDTH_o64_SCANF_IS_A_BROKEN_API SCNo64,
+                                       &$$->u.expression.u.constant) != 1) {
+                               parse_error(parser_ctx, "cannot scanf octal constant");
+                       }
+               }
+       |       HEXADECIMAL_CONSTANT
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_CONSTANT;
+                       if (sscanf(yylval.gs->s, "0x%" WIDTH_x64_SCANF_IS_A_BROKEN_API SCNx64,
+                                       &$$->u.expression.u.constant) != 1) {
+                               parse_error(parser_ctx, "cannot scanf hexadecimal constant");
+                       }
+               }
+       |       FLOAT_CONSTANT
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_FLOAT_CONSTANT;
+                       if (sscanf(yylval.gs->s, "%" WIDTH_lg_SCANF_IS_A_BROKEN_API "lg",
+                                       &$$->u.expression.u.float_constant) != 1) {
+                               parse_error(parser_ctx, "cannot scanf float constant");
+                       }
+               }
+       |       STRING_LITERAL_START DQUOTE
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_STRING;
+                       $$->u.expression.u.string = "";
+               }
+       |       STRING_LITERAL_START s_char_sequence DQUOTE
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_STRING;
+                       $$->u.expression.u.string = $2->s;
+               }
+       |       CHARACTER_CONSTANT_START c_char_sequence SQUOTE
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_STRING;
+                       $$->u.expression.u.string = $2->s;
+               }
+       |       LPAREN expression RPAREN
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_NESTED;
+                       $$->u.expression.u.child = $2;
+               }
+       ;
+
+identifiers
+       :       IDENTIFIER
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_IDENTIFIER;
+                       $$->u.expression.u.identifier = yylval.gs->s;
+               }
+       |       GLOBAL_IDENTIFIER
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_GLOBAL_IDENTIFIER;
+                       $$->u.expression.u.identifier = yylval.gs->s;
+               }
+       ;
+
+prefix_expression_rec
+       : LSBRAC unary_expression RSBRAC
+               {
+                       $$ = $2;
+               }
+       | LSBRAC unary_expression RSBRAC prefix_expression_rec
+               {
+                       $$ = $2;
+                       $$->u.expression.pre_op = AST_LINK_BRACKET;
+                       $$->u.expression.prev = $4;
+               }
+       ;
+
+prefix_expression
+       : identifiers
+               {
+                       $$ = $1;
+               }
+       | identifiers prefix_expression_rec
+               {
+                       $$ = $1;
+                       $$->u.expression.pre_op = AST_LINK_BRACKET;
+                       $$->u.expression.next_bracket = $2;
+               }
+       ;
+
+postfix_expression
+       : prefix_expression
+               {
+                       $$ = $1;
+               }
+       | postfix_expression DOT prefix_expression
+               {
+                       $$ = $3;
+                       $$->u.expression.post_op = AST_LINK_DOT;
+                       $$->u.expression.prev = $1;
+               }
+       | postfix_expression RARROW prefix_expression
+               {
+                       $$ = $3;
+                       $$->u.expression.post_op = AST_LINK_RARROW;
+                       $$->u.expression.prev = $1;
+               }
+       ;
+
+unary_expression
+       : postfix_expression
+               {       $$ = $1;                                        }
+       | primary_expression
+               {       $$ = $1;                                        }
+       | unary_operator unary_expression
+               {
+                       $$ = $1;
+                       $$->u.unary_op.child = $2;
+               }
+       ;
+
+unary_operator
+       : PLUS
+               {
+                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
+                       $$->u.unary_op.type = AST_UNARY_PLUS;
+               }
+       | MINUS
+               {
+                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
+                       $$->u.unary_op.type = AST_UNARY_MINUS;
+               }
+       | NOT_OP
+               {
+                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
+                       $$->u.unary_op.type = AST_UNARY_NOT;
+               }
+       | NOT_BIN
+               {
+                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
+                       $$->u.unary_op.type = AST_UNARY_BIT_NOT;
+               }
+       ;
+
+multiplicative_expression
+       : unary_expression
+               {       $$ = $1;                                        }
+       | multiplicative_expression STAR unary_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_MUL, $1, $3);
+               }
+       | multiplicative_expression DIV_OP unary_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_DIV, $1, $3);
+               }
+       | multiplicative_expression MOD_OP unary_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_MOD, $1, $3);
+               }
+       ;
+
+additive_expression
+       : multiplicative_expression
+               {       $$ = $1;                                        }
+       | additive_expression PLUS multiplicative_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_PLUS, $1, $3);
+               }
+       | additive_expression MINUS multiplicative_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_MINUS, $1, $3);
+               }
+       ;
+
+shift_expression
+       : additive_expression
+               {       $$ = $1;                                        }
+       | shift_expression LEFT_OP additive_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_BIT_LSHIFT, $1, $3);
+               }
+       | shift_expression RIGHT_OP additive_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_BIT_RSHIFT, $1, $3);
+               }
+       ;
+
+and_expression
+       : shift_expression
+               {       $$ = $1;                                        }
+       | and_expression AND_BIN shift_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_BIT_AND, $1, $3);
+               }
+       ;
+
+exclusive_or_expression
+       : and_expression
+               {       $$ = $1;                                        }
+       | exclusive_or_expression XOR_BIN and_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_BIT_XOR, $1, $3);
+               }
+       ;
+
+inclusive_or_expression
+       : exclusive_or_expression
+               {       $$ = $1;                                        }
+       | inclusive_or_expression OR_BIN exclusive_or_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_BIT_OR, $1, $3);
+               }
+       ;
+
+relational_expression
+       : inclusive_or_expression
+               {       $$ = $1;                                        }
+       | relational_expression LT_OP inclusive_or_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_LT, $1, $3);
+               }
+       | relational_expression GT_OP inclusive_or_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_GT, $1, $3);
+               }
+       | relational_expression LE_OP inclusive_or_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_LE, $1, $3);
+               }
+       | relational_expression GE_OP inclusive_or_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_GE, $1, $3);
+               }
+       ;
+
+equality_expression
+       : relational_expression
+               {       $$ = $1;                                        }
+       | equality_expression EQ_OP relational_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_EQ, $1, $3);
+               }
+       | equality_expression NE_OP relational_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_NE, $1, $3);
+               }
+       ;
+
+logical_and_expression
+       : equality_expression
+               {       $$ = $1;                                        }
+       | logical_and_expression AND_OP equality_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_AND, $1, $3);
+               }
+       ;
+
+logical_or_expression
+       : logical_and_expression
+               {       $$ = $1;                                        }
+       | logical_or_expression OR_OP logical_and_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_OR, $1, $3);
+               }
+       ;
+
+expression
+       : logical_or_expression
+               {       $$ = $1;                                        }
+       ;
+
+translation_unit
+       : expression
+               {
+                       parser_ctx->ast->root.u.root.child = $1;
+               }
+       ;
diff --git a/src/common/filter/filter-symbols.h b/src/common/filter/filter-symbols.h
new file mode 100644 (file)
index 0000000..031776d
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _FILTER_SYMBOLS_H
+#define _FILTER_SYMBOLS_H
+
+/*
+ * filter-symbols.h
+ *
+ * LTTng filter flex/bison symbol prefixes
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#define yy_create_buffer lttng_yy_create_buffer
+#define yy_delete_buffer lttng_yy_delete_buffer
+#define yy_flush_buffer lttng_yy_flush_buffer
+#define yy_scan_buffer lttng_yy_scan_buffer
+#define yy_scan_bytes lttng_yy_scan_bytes
+#define yy_scan_string lttng_yy_scan_string
+#define yy_switch_to_buffer lttng_yy_switch_to_buffer
+#define yyalloc lttng_yyalloc
+#define yyfree lttng_yyfree
+#define yyget_column lttng_yyget_column
+#define yyget_debug lttng_yyget_debug
+#define yyget_extra lttng_yyget_extra
+#define yyget_in lttng_yyget_in
+#define yyget_leng lttng_yyget_leng
+#define yyget_lineno lttng_yyget_lineno
+#define yyget_lval lttng_yyget_lval
+#define yyget_out lttng_yyget_out
+#define yyget_text lttng_yyget_text
+#define yylex_init lttng_yylex_init
+#define yypop_buffer_state lttng_yypop_buffer_state
+#define yypush_buffer_state lttng_yypush_buffer_state
+#define yyrealloc lttng_yyrealloc
+#define yyset_column lttng_yyset_column
+#define yyset_debug lttng_yyset_debug
+#define yyset_extra lttng_yyset_extra
+#define yyset_in lttng_yyset_in
+#define yyset_lineno lttng_yyset_lineno
+#define yyset_lval lttng_yyset_lval
+#define yyset_out lttng_yyset_out
+
+#endif /* _FILTER_SYMBOLS_H */
diff --git a/src/common/filter/filter-visitor-generate-bytecode.c b/src/common/filter/filter-visitor-generate-bytecode.c
new file mode 100644 (file)
index 0000000..699273c
--- /dev/null
@@ -0,0 +1,830 @@
+/*
+ * filter-visitor-generate-bytecode.c
+ *
+ * LTTng filter bytecode generation
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <common/align.h>
+#include <common/compat/string.h>
+
+#include "filter-bytecode.h"
+#include "filter-ir.h"
+#include "filter-ast.h"
+
+#include <common/macros.h>
+
+#ifndef max_t
+#define max_t(type, a, b)      ((type) ((a) > (b) ? (a) : (b)))
+#endif
+
+#define INIT_ALLOC_SIZE                4
+
+static
+int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
+               struct ir_op *node);
+
+static inline int get_count_order(unsigned int count)
+{
+       int order;
+
+       order = lttng_fls(count) - 1;
+       if (count & (count - 1))
+               order++;
+       return order;
+}
+
+static
+int bytecode_init(struct lttng_filter_bytecode_alloc **fb)
+{
+       uint32_t alloc_len;
+
+       alloc_len = sizeof(struct lttng_filter_bytecode_alloc) + INIT_ALLOC_SIZE;
+       *fb = calloc(alloc_len, 1);
+       if (!*fb) {
+               return -ENOMEM;
+       } else {
+               (*fb)->alloc_len = alloc_len;
+               return 0;
+       }
+}
+
+static
+int32_t bytecode_reserve(struct lttng_filter_bytecode_alloc **fb, uint32_t align, uint32_t len)
+{
+       int32_t ret;
+       uint32_t padding = offset_align((*fb)->b.len, align);
+       uint32_t new_len = (*fb)->b.len + padding + len;
+       uint32_t new_alloc_len = sizeof(struct lttng_filter_bytecode_alloc) + new_len;
+       uint32_t old_alloc_len = (*fb)->alloc_len;
+
+       if (new_len > LTTNG_FILTER_MAX_LEN)
+               return -EINVAL;
+
+       if (new_alloc_len > old_alloc_len) {
+               struct lttng_filter_bytecode_alloc *newptr;
+
+               new_alloc_len =
+                       max_t(uint32_t, 1U << get_count_order(new_alloc_len), old_alloc_len << 1);
+               newptr = realloc(*fb, new_alloc_len);
+               if (!newptr)
+                       return -ENOMEM;
+               *fb = newptr;
+               /* We zero directly the memory from start of allocation. */
+               memset(&((char *) *fb)[old_alloc_len], 0, new_alloc_len - old_alloc_len);
+               (*fb)->alloc_len = new_alloc_len;
+       }
+       (*fb)->b.len += padding;
+       ret = (*fb)->b.len;
+       (*fb)->b.len += len;
+       return ret;
+}
+
+static
+int bytecode_push(struct lttng_filter_bytecode_alloc **fb, const void *data,
+               uint32_t align, uint32_t len)
+{
+       int32_t offset;
+
+       offset = bytecode_reserve(fb, align, len);
+       if (offset < 0)
+               return offset;
+       memcpy(&(*fb)->b.data[offset], data, len);
+       return 0;
+}
+
+static
+int bytecode_push_logical(struct lttng_filter_bytecode_alloc **fb,
+               struct logical_op *data,
+               uint32_t align, uint32_t len,
+               uint16_t *skip_offset)
+{
+       int32_t offset;
+
+       offset = bytecode_reserve(fb, align, len);
+       if (offset < 0)
+               return offset;
+       memcpy(&(*fb)->b.data[offset], data, len);
+       *skip_offset =
+               (void *) &((struct logical_op *) &(*fb)->b.data[offset])->skip_offset
+                       - (void *) &(*fb)->b.data[0];
+       return 0;
+}
+
+static
+int bytecode_patch(struct lttng_filter_bytecode_alloc **fb,
+               const void *data,
+               uint16_t offset,
+               uint32_t len)
+{
+       if (offset >= (*fb)->b.len) {
+               return -EINVAL;
+       }
+       memcpy(&(*fb)->b.data[offset], data, len);
+       return 0;
+}
+
+static
+int visit_node_root(struct filter_parser_ctx *ctx, struct ir_op *node)
+{
+       int ret;
+       struct return_op insn;
+
+       /* Visit child */
+       ret = recursive_visit_gen_bytecode(ctx, node->u.root.child);
+       if (ret)
+               return ret;
+
+       /* Generate end of bytecode instruction */
+       insn.op = FILTER_OP_RETURN;
+       return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+}
+
+static
+int append_str(char **s, const char *append)
+{
+       char *old = *s;
+       char *new;
+       size_t oldlen = (old == NULL) ? 0 : strlen(old);
+       size_t appendlen = strlen(append);
+
+       new = calloc(oldlen + appendlen + 1, 1);
+       if (!new) {
+               return -ENOMEM;
+       }
+       if (oldlen) {
+               strcpy(new, old);
+       }
+       strcat(new, append);
+       *s = new;
+       free(old);
+       return 0;
+}
+
+/*
+ * 1: match
+ * 0: no match
+ * < 0: error
+ */
+static
+int load_expression_legacy_match(const struct ir_load_expression *exp,
+               enum filter_op *op_type,
+               char **symbol)
+{
+       const struct ir_load_expression_op *op;
+       bool need_dot = false;
+
+       op = exp->child;
+       switch (op->type) {
+       case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
+               *op_type = FILTER_OP_GET_CONTEXT_REF;
+               if (append_str(symbol, "$ctx.")) {
+                       return -ENOMEM;
+               }
+               need_dot = false;
+               break;
+       case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
+               *op_type = FILTER_OP_GET_CONTEXT_REF;
+               if (append_str(symbol, "$app.")) {
+                       return -ENOMEM;
+               }
+               need_dot = false;
+               break;
+       case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
+               *op_type = FILTER_OP_LOAD_FIELD_REF;
+               need_dot = false;
+               break;
+
+       case IR_LOAD_EXPRESSION_GET_SYMBOL:
+       case IR_LOAD_EXPRESSION_GET_INDEX:
+       case IR_LOAD_EXPRESSION_LOAD_FIELD:
+       default:
+               return 0;       /* no match */
+       }
+
+       for (;;) {
+               op = op->next;
+               if (!op) {
+                       return 0;       /* no match */
+               }
+               switch (op->type) {
+               case IR_LOAD_EXPRESSION_LOAD_FIELD:
+                       goto end;
+               case IR_LOAD_EXPRESSION_GET_SYMBOL:
+                       if (need_dot && append_str(symbol, ".")) {
+                               return -ENOMEM;
+                       }
+                       if (append_str(symbol, op->u.symbol)) {
+                               return -ENOMEM;
+                       }
+                       break;
+               default:
+                       return 0;        /* no match */
+               }
+               need_dot = true;
+       }
+end:
+       return 1;       /* Legacy match */
+}
+
+/*
+ * 1: legacy match
+ * 0: no legacy match
+ * < 0: error
+ */
+static
+int visit_node_load_expression_legacy(struct filter_parser_ctx *ctx,
+               const struct ir_load_expression *exp,
+               const struct ir_load_expression_op *op)
+{
+       struct load_op *insn = NULL;
+       uint32_t insn_len = sizeof(struct load_op)
+               + sizeof(struct field_ref);
+       struct field_ref ref_offset;
+       uint32_t reloc_offset_u32;
+       uint16_t reloc_offset;
+       enum filter_op op_type;
+       char *symbol = NULL;
+       int ret;
+
+       ret = load_expression_legacy_match(exp, &op_type, &symbol);
+       if (ret <= 0) {
+               goto end;
+       }
+       insn = calloc(insn_len, 1);
+       if (!insn) {
+               ret = -ENOMEM;
+               goto end;
+       }
+       insn->op = op_type;
+       ref_offset.offset = (uint16_t) -1U;
+       memcpy(insn->data, &ref_offset, sizeof(ref_offset));
+       /* reloc_offset points to struct load_op */
+       reloc_offset_u32 = bytecode_get_len(&ctx->bytecode->b);
+       if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) {
+               ret = -EINVAL;
+               goto end;
+       }
+       reloc_offset = (uint16_t) reloc_offset_u32;
+       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+       if (ret) {
+               goto end;
+       }
+       /* append reloc */
+       ret = bytecode_push(&ctx->bytecode_reloc, &reloc_offset,
+                               1, sizeof(reloc_offset));
+       if (ret) {
+               goto end;
+       }
+       ret = bytecode_push(&ctx->bytecode_reloc, symbol,
+                               1, strlen(symbol) + 1);
+       if (ret) {
+               goto end;
+       }
+       ret = 1;        /* legacy */
+end:
+       free(insn);
+       free(symbol);
+       return ret;
+}
+
+static
+int visit_node_load_expression(struct filter_parser_ctx *ctx,
+               const struct ir_op *node)
+{
+       struct ir_load_expression *exp;
+       struct ir_load_expression_op *op;
+       int ret;
+
+       exp = node->u.load.u.expression;
+       if (!exp) {
+               return -EINVAL;
+       }
+       op = exp->child;
+       if (!op) {
+               return -EINVAL;
+       }
+
+       /*
+        * TODO: if we remove legacy load for application contexts, we
+        * need to update session bytecode parser as well.
+        */
+       ret = visit_node_load_expression_legacy(ctx, exp, op);
+       if (ret < 0) {
+               return ret;
+       }
+       if (ret > 0) {
+               return 0;       /* legacy */
+       }
+
+       for (; op != NULL; op = op->next) {
+               switch (op->type) {
+               case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op);
+                       int ret;
+
+                       insn = calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = FILTER_OP_GET_CONTEXT_ROOT;
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op);
+                       int ret;
+
+                       insn = calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = FILTER_OP_GET_APP_CONTEXT_ROOT;
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op);
+                       int ret;
+
+                       insn = calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = FILTER_OP_GET_PAYLOAD_ROOT;
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_GET_SYMBOL:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op)
+                               + sizeof(struct get_symbol);
+                       struct get_symbol symbol_offset;
+                       uint32_t reloc_offset_u32;
+                       uint16_t reloc_offset;
+                       uint32_t bytecode_reloc_offset_u32;
+                       int ret;
+
+                       insn = calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = FILTER_OP_GET_SYMBOL;
+                       bytecode_reloc_offset_u32 =
+                                       bytecode_get_len(&ctx->bytecode_reloc->b)
+                                       + sizeof(reloc_offset);
+                       symbol_offset.offset =
+                                       (uint16_t) bytecode_reloc_offset_u32;
+                       memcpy(insn->data, &symbol_offset,
+                                       sizeof(symbol_offset));
+                       /* reloc_offset points to struct load_op */
+                       reloc_offset_u32 = bytecode_get_len(&ctx->bytecode->b);
+                       if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) {
+                               free(insn);
+                               return -EINVAL;
+                       }
+                       reloc_offset = (uint16_t) reloc_offset_u32;
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       if (ret) {
+                               free(insn);
+                               return ret;
+                       }
+                       /* append reloc */
+                       ret = bytecode_push(&ctx->bytecode_reloc, &reloc_offset,
+                                       1, sizeof(reloc_offset));
+                       if (ret) {
+                               free(insn);
+                               return ret;
+                       }
+                       ret = bytecode_push(&ctx->bytecode_reloc,
+                                       op->u.symbol,
+                                       1, strlen(op->u.symbol) + 1);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_GET_INDEX:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op)
+                               + sizeof(struct get_index_u64);
+                       struct get_index_u64 index;
+                       int ret;
+
+                       insn = calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = FILTER_OP_GET_INDEX_U64;
+                       index.index = op->u.index;
+                       memcpy(insn->data, &index, sizeof(index));
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_LOAD_FIELD:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op);
+                       int ret;
+
+                       insn = calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = FILTER_OP_LOAD_FIELD;
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               }
+       }
+       return 0;
+}
+
+static
+int visit_node_load(struct filter_parser_ctx *ctx, struct ir_op *node)
+{
+       int ret;
+
+       switch (node->data_type) {
+       case IR_DATA_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] Unknown data type in %s\n",
+                       __func__);
+               return -EINVAL;
+
+       case IR_DATA_STRING:
+       {
+               struct load_op *insn;
+               uint32_t insn_len = sizeof(struct load_op)
+                       + strlen(node->u.load.u.string.value) + 1;
+
+               insn = calloc(insn_len, 1);
+               if (!insn)
+                       return -ENOMEM;
+
+               switch (node->u.load.u.string.type) {
+               case IR_LOAD_STRING_TYPE_GLOB_STAR:
+                       /*
+                        * We explicitly tell the interpreter here that
+                        * this load is a full star globbing pattern so
+                        * that the appropriate matching function can be
+                        * called. Also, see comment below.
+                        */
+                       insn->op = FILTER_OP_LOAD_STAR_GLOB_STRING;
+                       break;
+               default:
+                       /*
+                        * This is the "legacy" string, which includes
+                        * star globbing patterns with a star only at
+                        * the end. Both "plain" and "star at the end"
+                        * literal strings are handled at the same place
+                        * by the tracer's filter bytecode interpreter,
+                        * whereas full star globbing patterns (stars
+                        * can be anywhere in the string) is a special
+                        * case.
+                        */
+                       insn->op = FILTER_OP_LOAD_STRING;
+                       break;
+               }
+
+               strcpy(insn->data, node->u.load.u.string.value);
+               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+               free(insn);
+               return ret;
+       }
+       case IR_DATA_NUMERIC:
+       {
+               struct load_op *insn;
+               uint32_t insn_len = sizeof(struct load_op)
+                       + sizeof(struct literal_numeric);
+
+               insn = calloc(insn_len, 1);
+               if (!insn)
+                       return -ENOMEM;
+               insn->op = FILTER_OP_LOAD_S64;
+               memcpy(insn->data, &node->u.load.u.num, sizeof(int64_t));
+               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+               free(insn);
+               return ret;
+       }
+       case IR_DATA_FLOAT:
+       {
+               struct load_op *insn;
+               uint32_t insn_len = sizeof(struct load_op)
+                       + sizeof(struct literal_double);
+
+               insn = calloc(insn_len, 1);
+               if (!insn)
+                       return -ENOMEM;
+               insn->op = FILTER_OP_LOAD_DOUBLE;
+               memcpy(insn->data, &node->u.load.u.flt, sizeof(double));
+               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+               free(insn);
+               return ret;
+       }
+       case IR_DATA_EXPRESSION:
+               return visit_node_load_expression(ctx, node);
+       }
+}
+
+static
+int visit_node_unary(struct filter_parser_ctx *ctx, struct ir_op *node)
+{
+       int ret;
+       struct unary_op insn;
+
+       /* Visit child */
+       ret = recursive_visit_gen_bytecode(ctx, node->u.unary.child);
+       if (ret)
+               return ret;
+
+       /* Generate end of bytecode instruction */
+       switch (node->u.unary.type) {
+       case AST_UNARY_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] Unknown unary node type in %s\n",
+                       __func__);
+               return -EINVAL;
+       case AST_UNARY_PLUS:
+               /* Nothing to do. */
+               return 0;
+       case AST_UNARY_MINUS:
+               insn.op = FILTER_OP_UNARY_MINUS;
+               return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+       case AST_UNARY_NOT:
+               insn.op = FILTER_OP_UNARY_NOT;
+               return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+       case AST_UNARY_BIT_NOT:
+               insn.op = FILTER_OP_UNARY_BIT_NOT;
+               return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+       }
+}
+
+/*
+ * Binary comparator nesting is disallowed. This allows fitting into
+ * only 2 registers.
+ */
+static
+int visit_node_binary(struct filter_parser_ctx *ctx, struct ir_op *node)
+{
+       int ret;
+       struct binary_op insn;
+
+       /* Visit child */
+       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.left);
+       if (ret)
+               return ret;
+       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.right);
+       if (ret)
+               return ret;
+
+       switch (node->u.binary.type) {
+       case AST_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] Unknown unary node type in %s\n",
+                       __func__);
+               return -EINVAL;
+
+       case AST_OP_AND:
+       case AST_OP_OR:
+               fprintf(stderr, "[error] Unexpected logical node type in %s\n",
+                       __func__);
+               return -EINVAL;
+
+       case AST_OP_MUL:
+               insn.op = FILTER_OP_MUL;
+               break;
+       case AST_OP_DIV:
+               insn.op = FILTER_OP_DIV;
+               break;
+       case AST_OP_MOD:
+               insn.op = FILTER_OP_MOD;
+               break;
+       case AST_OP_PLUS:
+               insn.op = FILTER_OP_PLUS;
+               break;
+       case AST_OP_MINUS:
+               insn.op = FILTER_OP_MINUS;
+               break;
+       case AST_OP_BIT_RSHIFT:
+               insn.op = FILTER_OP_BIT_RSHIFT;
+               break;
+       case AST_OP_BIT_LSHIFT:
+               insn.op = FILTER_OP_BIT_LSHIFT;
+               break;
+       case AST_OP_BIT_AND:
+               insn.op = FILTER_OP_BIT_AND;
+               break;
+       case AST_OP_BIT_OR:
+               insn.op = FILTER_OP_BIT_OR;
+               break;
+       case AST_OP_BIT_XOR:
+               insn.op = FILTER_OP_BIT_XOR;
+               break;
+
+       case AST_OP_EQ:
+               insn.op = FILTER_OP_EQ;
+               break;
+       case AST_OP_NE:
+               insn.op = FILTER_OP_NE;
+               break;
+       case AST_OP_GT:
+               insn.op = FILTER_OP_GT;
+               break;
+       case AST_OP_LT:
+               insn.op = FILTER_OP_LT;
+               break;
+       case AST_OP_GE:
+               insn.op = FILTER_OP_GE;
+               break;
+       case AST_OP_LE:
+               insn.op = FILTER_OP_LE;
+               break;
+       }
+       return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+}
+
+/*
+ * A logical op always return a s64 (1 or 0).
+ */
+static
+int visit_node_logical(struct filter_parser_ctx *ctx, struct ir_op *node)
+{
+       int ret;
+       struct logical_op insn;
+       uint16_t skip_offset_loc;
+       uint16_t target_loc;
+
+       /* Visit left child */
+       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.left);
+       if (ret)
+               return ret;
+       /* Cast to s64 if float or field ref */
+       if ((node->u.binary.left->data_type == IR_DATA_FIELD_REF
+                               || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
+                               || node->u.binary.left->data_type == IR_DATA_EXPRESSION)
+                       || node->u.binary.left->data_type == IR_DATA_FLOAT) {
+               struct cast_op cast_insn;
+
+               if (node->u.binary.left->data_type == IR_DATA_FIELD_REF
+                               || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
+                               || node->u.binary.left->data_type == IR_DATA_EXPRESSION) {
+                       cast_insn.op = FILTER_OP_CAST_TO_S64;
+               } else {
+                       cast_insn.op = FILTER_OP_CAST_DOUBLE_TO_S64;
+               }
+               ret = bytecode_push(&ctx->bytecode, &cast_insn,
+                                       1, sizeof(cast_insn));
+               if (ret)
+                       return ret;
+       }
+       switch (node->u.logical.type) {
+       default:
+               fprintf(stderr, "[error] Unknown node type in %s\n",
+                       __func__);
+               return -EINVAL;
+
+       case AST_OP_AND:
+               insn.op = FILTER_OP_AND;
+               break;
+       case AST_OP_OR:
+               insn.op = FILTER_OP_OR;
+               break;
+       }
+       insn.skip_offset = (uint16_t) -1UL;     /* Temporary */
+       ret = bytecode_push_logical(&ctx->bytecode, &insn, 1, sizeof(insn),
+                       &skip_offset_loc);
+       if (ret)
+               return ret;
+       /* Visit right child */
+       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.right);
+       if (ret)
+               return ret;
+       /* Cast to s64 if float or field ref */
+       if ((node->u.binary.right->data_type == IR_DATA_FIELD_REF
+                               || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
+                               || node->u.binary.right->data_type == IR_DATA_EXPRESSION)
+                       || node->u.binary.right->data_type == IR_DATA_FLOAT) {
+               struct cast_op cast_insn;
+
+               if (node->u.binary.right->data_type == IR_DATA_FIELD_REF
+                               || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
+                               || node->u.binary.right->data_type == IR_DATA_EXPRESSION) {
+                       cast_insn.op = FILTER_OP_CAST_TO_S64;
+               } else {
+                       cast_insn.op = FILTER_OP_CAST_DOUBLE_TO_S64;
+               }
+               ret = bytecode_push(&ctx->bytecode, &cast_insn,
+                                       1, sizeof(cast_insn));
+               if (ret)
+                       return ret;
+       }
+       /* We now know where the logical op can skip. */
+       target_loc = (uint16_t) bytecode_get_len(&ctx->bytecode->b);
+       ret = bytecode_patch(&ctx->bytecode,
+                       &target_loc,                    /* Offset to jump to */
+                       skip_offset_loc,                /* Where to patch */
+                       sizeof(uint16_t));
+       return ret;
+}
+
+/*
+ * Postorder traversal of the tree. We need the children result before
+ * we can evaluate the parent.
+ */
+static
+int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
+               struct ir_op *node)
+{
+       switch (node->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] Unknown node type in %s\n",
+                       __func__);
+               return -EINVAL;
+
+       case IR_OP_ROOT:
+               return visit_node_root(ctx, node);
+       case IR_OP_LOAD:
+               return visit_node_load(ctx, node);
+       case IR_OP_UNARY:
+               return visit_node_unary(ctx, node);
+       case IR_OP_BINARY:
+               return visit_node_binary(ctx, node);
+       case IR_OP_LOGICAL:
+               return visit_node_logical(ctx, node);
+       }
+}
+
+LTTNG_HIDDEN
+void filter_bytecode_free(struct filter_parser_ctx *ctx)
+{
+       if (!ctx) {
+               return;
+       }
+
+       if (ctx->bytecode) {
+               free(ctx->bytecode);
+               ctx->bytecode = NULL;
+       }
+
+       if (ctx->bytecode_reloc) {
+               free(ctx->bytecode_reloc);
+               ctx->bytecode_reloc = NULL;
+       }
+}
+
+LTTNG_HIDDEN
+int filter_visitor_bytecode_generate(struct filter_parser_ctx *ctx)
+{
+       int ret;
+
+       ret = bytecode_init(&ctx->bytecode);
+       if (ret)
+               return ret;
+       ret = bytecode_init(&ctx->bytecode_reloc);
+       if (ret)
+               goto error;
+       ret = recursive_visit_gen_bytecode(ctx, ctx->ir_root);
+       if (ret)
+               goto error;
+
+       /* Finally, append symbol table to bytecode */
+       ctx->bytecode->b.reloc_table_offset = bytecode_get_len(&ctx->bytecode->b);
+       return bytecode_push(&ctx->bytecode, ctx->bytecode_reloc->b.data,
+                       1, bytecode_get_len(&ctx->bytecode_reloc->b));
+
+error:
+       filter_bytecode_free(ctx);
+       return ret;
+}
diff --git a/src/common/filter/filter-visitor-generate-ir.c b/src/common/filter/filter-visitor-generate-ir.c
new file mode 100644 (file)
index 0000000..11c6b61
--- /dev/null
@@ -0,0 +1,909 @@
+/*
+ * filter-visitor-generate-ir.c
+ *
+ * LTTng filter generate intermediate representation
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include "filter-ast.h"
+#include "filter-parser.h"
+#include "filter-ir.h"
+
+#include <common/macros.h>
+#include <common/string-utils/string-utils.h>
+
+static
+struct ir_op *generate_ir_recursive(struct filter_parser_ctx *ctx,
+               struct filter_node *node, enum ir_side side);
+
+static
+struct ir_op *make_op_root(struct ir_op *child, enum ir_side side)
+{
+       struct ir_op *op;
+
+       op = calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       switch (child->data_type) {
+       case IR_DATA_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] Unknown root child data type\n");
+               free(op);
+               return NULL;
+       case IR_DATA_STRING:
+               fprintf(stderr, "[error] String cannot be root data type\n");
+               free(op);
+               return NULL;
+       case IR_DATA_NUMERIC:
+       case IR_DATA_FIELD_REF:
+       case IR_DATA_GET_CONTEXT_REF:
+       case IR_DATA_EXPRESSION:
+               /* ok */
+               break;
+       }
+       op->op = IR_OP_ROOT;
+       op->side = side;
+       op->data_type = child->data_type;
+       op->signedness = child->signedness;
+       op->u.root.child = child;
+       return op;
+}
+
+static
+enum ir_load_string_type get_literal_string_type(const char *string)
+{
+       assert(string);
+
+       if (strutils_is_star_glob_pattern(string)) {
+               if (strutils_is_star_at_the_end_only_glob_pattern(string)) {
+                       return IR_LOAD_STRING_TYPE_GLOB_STAR_END;
+               }
+
+               return IR_LOAD_STRING_TYPE_GLOB_STAR;
+       }
+
+       return IR_LOAD_STRING_TYPE_PLAIN;
+}
+
+static
+struct ir_op *make_op_load_string(const char *string, enum ir_side side)
+{
+       struct ir_op *op;
+
+       op = calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_LOAD;
+       op->data_type = IR_DATA_STRING;
+       op->signedness = IR_SIGN_UNKNOWN;
+       op->side = side;
+       op->u.load.u.string.type = get_literal_string_type(string);
+       op->u.load.u.string.value = strdup(string);
+       if (!op->u.load.u.string.value) {
+               free(op);
+               return NULL;
+       }
+       return op;
+}
+
+static
+struct ir_op *make_op_load_numeric(int64_t v, enum ir_side side)
+{
+       struct ir_op *op;
+
+       op = calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_LOAD;
+       op->data_type = IR_DATA_NUMERIC;
+       /* TODO: for now, all numeric values are signed */
+       op->signedness = IR_SIGNED;
+       op->side = side;
+       op->u.load.u.num = v;
+       return op;
+}
+
+static
+struct ir_op *make_op_load_float(double v, enum ir_side side)
+{
+       struct ir_op *op;
+
+       op = calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_LOAD;
+       op->data_type = IR_DATA_FLOAT;
+       op->signedness = IR_SIGN_UNKNOWN;
+       op->side = side;
+       op->u.load.u.flt = v;
+       return op;
+}
+
+static
+void free_load_expression(struct ir_load_expression *load_expression)
+{
+       struct ir_load_expression_op *exp_op;
+
+       if (!load_expression)
+               return;
+       exp_op = load_expression->child;
+       for (;;) {
+               struct ir_load_expression_op *prev_exp_op;
+
+               if (!exp_op)
+                       break;
+               switch (exp_op->type) {
+               case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
+               case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
+               case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
+               case IR_LOAD_EXPRESSION_GET_INDEX:
+               case IR_LOAD_EXPRESSION_LOAD_FIELD:
+                       break;
+               case IR_LOAD_EXPRESSION_GET_SYMBOL:
+                       free(exp_op->u.symbol);
+                       break;
+               }
+               prev_exp_op = exp_op;
+               exp_op = exp_op->next;
+               free(prev_exp_op);
+       }
+       free(load_expression);
+}
+
+/*
+ * Returns the first node of the chain, after initializing the next
+ * pointers.
+ */
+static
+struct filter_node *load_expression_get_forward_chain(struct filter_node *node)
+{
+       struct filter_node *prev_node;
+
+       for (;;) {
+               assert(node->type == NODE_EXPRESSION);
+               prev_node = node;
+               node = node->u.expression.prev;
+               if (!node) {
+                       break;
+               }
+               node->u.expression.next = prev_node;
+       }
+       return prev_node;
+}
+
+static
+struct ir_load_expression *create_load_expression(struct filter_node *node)
+{
+       struct ir_load_expression *load_exp;
+       struct ir_load_expression_op *load_exp_op, *prev_op;
+       const char *str;
+
+       /* Get forward chain. */
+       node = load_expression_get_forward_chain(node);
+       if (!node)
+               return NULL;
+       load_exp = calloc(sizeof(struct ir_load_expression), 1);
+       if (!load_exp)
+               return NULL;
+
+       /* Root */
+       load_exp_op = calloc(sizeof(struct ir_load_expression_op), 1);
+       if (!load_exp_op)
+               goto error;
+       load_exp->child = load_exp_op;
+       str = node->u.expression.u.string;
+       if (!strcmp(str, "$ctx")) {
+               load_exp_op->type = IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT;
+               node = node->u.expression.next;
+               if (!node) {
+                       fprintf(stderr, "[error] Expecting identifier after \'%s\'\n", str);
+                       goto error;
+               }
+               str = node->u.expression.u.string;
+       } else if (!strcmp(str, "$app")) {
+               load_exp_op->type = IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT;
+               node = node->u.expression.next;
+               if (!node) {
+                       fprintf(stderr, "[error] Expecting identifier after \'%s\'\n", str);
+                       goto error;
+               }
+               str = node->u.expression.u.string;
+       } else if (str[0] == '$') {
+               fprintf(stderr, "[error] Unexpected identifier \'%s\'\n", str);
+               goto error;
+       } else {
+               load_exp_op->type = IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT;
+       }
+
+       for (;;) {
+               struct filter_node *bracket_node;
+
+               prev_op = load_exp_op;
+               load_exp_op = calloc(sizeof(struct ir_load_expression_op), 1);
+               if (!load_exp_op)
+                       goto error;
+               prev_op->next = load_exp_op;
+               load_exp_op->type = IR_LOAD_EXPRESSION_GET_SYMBOL;
+               load_exp_op->u.symbol = strdup(str);
+               if (!load_exp_op->u.symbol)
+                       goto error;
+
+               /* Explore brackets from current node. */
+               for (bracket_node = node->u.expression.next_bracket;
+                               bracket_node != NULL;
+                               bracket_node = bracket_node->u.expression.next_bracket) {
+                       prev_op = load_exp_op;
+                       load_exp_op = calloc(sizeof(struct ir_load_expression_op), 1);
+                       if (!load_exp_op)
+                               goto error;
+                       prev_op->next = load_exp_op;
+                       load_exp_op->type = IR_LOAD_EXPRESSION_GET_INDEX;
+                       load_exp_op->u.index = bracket_node->u.expression.u.constant;
+               }
+               /* Go to next chain element. */
+               node = node->u.expression.next;
+               if (!node)
+                       break;
+               str = node->u.expression.u.string;
+       }
+       /* Add final load field */
+       prev_op = load_exp_op;
+       load_exp_op = calloc(sizeof(struct ir_load_expression_op), 1);
+       if (!load_exp_op)
+               goto error;
+       prev_op->next = load_exp_op;
+       load_exp_op->type = IR_LOAD_EXPRESSION_LOAD_FIELD;
+       return load_exp;
+
+error:
+       free_load_expression(load_exp);
+       return NULL;
+}
+
+static
+struct ir_op *make_op_load_expression(struct filter_node *node,
+               enum ir_side side)
+{
+       struct ir_op *op;
+
+       op = calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_LOAD;
+       op->data_type = IR_DATA_EXPRESSION;
+       op->signedness = IR_SIGN_DYN;
+       op->side = side;
+       op->u.load.u.expression = create_load_expression(node);
+       if (!op->u.load.u.expression) {
+               goto error;
+       }
+       return op;
+
+error:
+       free_load_expression(op->u.load.u.expression);
+       free(op);
+       return NULL;
+}
+
+static
+struct ir_op *make_op_unary(enum unary_op_type unary_op_type,
+                       const char *op_str, enum ir_op_signedness signedness,
+                       struct ir_op *child, enum ir_side side)
+{
+       struct ir_op *op = NULL;
+
+       if (child->data_type == IR_DATA_STRING) {
+               fprintf(stderr, "[error] unary operation '%s' not allowed on string literal\n", op_str);
+               goto error;
+       }
+
+       op = calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_UNARY;
+       op->data_type = child->data_type;
+       op->signedness = signedness;
+       op->side = side;
+       op->u.unary.type = unary_op_type;
+       op->u.unary.child = child;
+       return op;
+
+error:
+       free(op);
+       return NULL;
+}
+
+/*
+ * unary + is pretty much useless.
+ */
+static
+struct ir_op *make_op_unary_plus(struct ir_op *child, enum ir_side side)
+{
+       return make_op_unary(AST_UNARY_PLUS, "+", child->signedness,
+                       child, side);
+}
+
+static
+struct ir_op *make_op_unary_minus(struct ir_op *child, enum ir_side side)
+{
+       return make_op_unary(AST_UNARY_MINUS, "-", child->signedness,
+                       child, side);
+}
+
+static
+struct ir_op *make_op_unary_not(struct ir_op *child, enum ir_side side)
+{
+       return make_op_unary(AST_UNARY_NOT, "!", child->signedness,
+                       child, side);
+}
+
+static
+struct ir_op *make_op_unary_bit_not(struct ir_op *child, enum ir_side side)
+{
+       return make_op_unary(AST_UNARY_BIT_NOT, "~", child->signedness,
+                       child, side);
+}
+
+static
+struct ir_op *make_op_binary_compare(enum op_type bin_op_type,
+               const char *op_str, struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       struct ir_op *op = NULL;
+
+       if (left->data_type == IR_DATA_UNKNOWN
+               || right->data_type == IR_DATA_UNKNOWN) {
+               fprintf(stderr, "[error] binary operation '%s' has unknown operand type\n", op_str);
+               goto error;
+
+       }
+       if ((left->data_type == IR_DATA_STRING
+               && (right->data_type == IR_DATA_NUMERIC || right->data_type == IR_DATA_FLOAT))
+               || ((left->data_type == IR_DATA_NUMERIC || left->data_type == IR_DATA_FLOAT) &&
+                       right->data_type == IR_DATA_STRING)) {
+               fprintf(stderr, "[error] binary operation '%s' operand type mismatch\n", op_str);
+               goto error;
+       }
+
+       op = calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_BINARY;
+       op->u.binary.type = bin_op_type;
+       op->u.binary.left = left;
+       op->u.binary.right = right;
+
+       /* we return a boolean, represented as signed numeric */
+       op->data_type = IR_DATA_NUMERIC;
+       op->signedness = IR_SIGNED;
+       op->side = side;
+
+       return op;
+
+error:
+       free(op);
+       return NULL;
+}
+
+static
+struct ir_op *make_op_binary_eq(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_compare(AST_OP_EQ, "==", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_ne(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_compare(AST_OP_NE, "!=", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_gt(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_compare(AST_OP_GT, ">", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_lt(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_compare(AST_OP_LT, "<", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_ge(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_compare(AST_OP_GE, ">=", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_le(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_compare(AST_OP_LE, "<=", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_logical(enum op_type bin_op_type,
+               const char *op_str, struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       struct ir_op *op = NULL;
+
+       if (left->data_type == IR_DATA_UNKNOWN
+               || right->data_type == IR_DATA_UNKNOWN) {
+               fprintf(stderr, "[error] binary operation '%s' has unknown operand type\n", op_str);
+               goto error;
+
+       }
+       if (left->data_type == IR_DATA_STRING
+               || right->data_type == IR_DATA_STRING) {
+               fprintf(stderr, "[error] logical binary operation '%s' cannot have string operand\n", op_str);
+               goto error;
+       }
+
+       op = calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_LOGICAL;
+       op->u.binary.type = bin_op_type;
+       op->u.binary.left = left;
+       op->u.binary.right = right;
+
+       /* we return a boolean, represented as signed numeric */
+       op->data_type = IR_DATA_NUMERIC;
+       op->signedness = IR_SIGNED;
+       op->side = side;
+
+       return op;
+
+error:
+       free(op);
+       return NULL;
+}
+
+static
+struct ir_op *make_op_binary_bitwise(enum op_type bin_op_type,
+               const char *op_str, struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       struct ir_op *op = NULL;
+
+       if (left->data_type == IR_DATA_UNKNOWN
+               || right->data_type == IR_DATA_UNKNOWN) {
+               fprintf(stderr, "[error] bitwise binary operation '%s' has unknown operand type\n", op_str);
+               goto error;
+
+       }
+       if (left->data_type == IR_DATA_STRING
+               || right->data_type == IR_DATA_STRING) {
+               fprintf(stderr, "[error] bitwise binary operation '%s' cannot have string operand\n", op_str);
+               goto error;
+       }
+       if (left->data_type == IR_DATA_FLOAT
+               || right->data_type == IR_DATA_FLOAT) {
+               fprintf(stderr, "[error] bitwise binary operation '%s' cannot have floating point operand\n", op_str);
+               goto error;
+       }
+
+       op = calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_BINARY;
+       op->u.binary.type = bin_op_type;
+       op->u.binary.left = left;
+       op->u.binary.right = right;
+
+       /* we return a signed numeric */
+       op->data_type = IR_DATA_NUMERIC;
+       op->signedness = IR_SIGNED;
+       op->side = side;
+
+       return op;
+
+error:
+       free(op);
+       return NULL;
+}
+
+static
+struct ir_op *make_op_binary_logical_and(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_logical(AST_OP_AND, "&&", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_logical_or(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_logical(AST_OP_OR, "||", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_bitwise_rshift(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_bitwise(AST_OP_BIT_RSHIFT, ">>", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_bitwise_lshift(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_bitwise(AST_OP_BIT_LSHIFT, "<<", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_bitwise_and(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_bitwise(AST_OP_BIT_AND, "&", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_bitwise_or(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_bitwise(AST_OP_BIT_OR, "|", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_bitwise_xor(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_bitwise(AST_OP_BIT_XOR, "^", left, right, side);
+}
+
+static
+void filter_free_ir_recursive(struct ir_op *op)
+{
+       if (!op)
+               return;
+       switch (op->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] Unknown op type in %s\n",
+                       __func__);
+               break;
+       case IR_OP_ROOT:
+               filter_free_ir_recursive(op->u.root.child);
+               break;
+       case IR_OP_LOAD:
+               switch (op->data_type) {
+               case IR_DATA_STRING:
+                       free(op->u.load.u.string.value);
+                       break;
+               case IR_DATA_FIELD_REF:         /* fall-through */
+               case IR_DATA_GET_CONTEXT_REF:
+                       free(op->u.load.u.ref);
+                       break;
+               case IR_DATA_EXPRESSION:
+                       free_load_expression(op->u.load.u.expression);
+               default:
+                       break;
+               }
+               break;
+       case IR_OP_UNARY:
+               filter_free_ir_recursive(op->u.unary.child);
+               break;
+       case IR_OP_BINARY:
+               filter_free_ir_recursive(op->u.binary.left);
+               filter_free_ir_recursive(op->u.binary.right);
+               break;
+       case IR_OP_LOGICAL:
+               filter_free_ir_recursive(op->u.logical.left);
+               filter_free_ir_recursive(op->u.logical.right);
+               break;
+       }
+       free(op);
+}
+
+static
+struct ir_op *make_expression(struct filter_parser_ctx *ctx,
+               struct filter_node *node, enum ir_side side)
+{
+       switch (node->u.expression.type) {
+       case AST_EXP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown expression type\n", __func__);
+               return NULL;
+
+       case AST_EXP_STRING:
+               return make_op_load_string(node->u.expression.u.string, side);
+       case AST_EXP_CONSTANT:
+               return make_op_load_numeric(node->u.expression.u.constant,
+                                       side);
+       case AST_EXP_FLOAT_CONSTANT:
+               return make_op_load_float(node->u.expression.u.float_constant,
+                                       side);
+       case AST_EXP_IDENTIFIER:
+       case AST_EXP_GLOBAL_IDENTIFIER:
+               return make_op_load_expression(node, side);
+       case AST_EXP_NESTED:
+               return generate_ir_recursive(ctx, node->u.expression.u.child,
+                                       side);
+       }
+}
+
+static
+struct ir_op *make_op(struct filter_parser_ctx *ctx,
+               struct filter_node *node, enum ir_side side)
+{
+       struct ir_op *op = NULL, *lchild, *rchild;
+       const char *op_str = "?";
+
+       switch (node->u.op.type) {
+       case AST_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown binary op type\n", __func__);
+               return NULL;
+
+       /*
+        * The following binary operators other than comparators and
+        * logical and/or are not supported yet.
+        */
+       case AST_OP_MUL:
+               op_str = "*";
+               goto error_not_supported;
+       case AST_OP_DIV:
+               op_str = "/";
+               goto error_not_supported;
+       case AST_OP_MOD:
+               op_str = "%";
+               goto error_not_supported;
+       case AST_OP_PLUS:
+               op_str = "+";
+               goto error_not_supported;
+       case AST_OP_MINUS:
+               op_str = "-";
+               goto error_not_supported;
+
+       case AST_OP_BIT_RSHIFT:
+       case AST_OP_BIT_LSHIFT:
+       case AST_OP_BIT_AND:
+       case AST_OP_BIT_OR:
+       case AST_OP_BIT_XOR:
+               lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
+               if (!lchild)
+                       return NULL;
+               rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_RIGHT);
+               if (!rchild) {
+                       filter_free_ir_recursive(lchild);
+                       return NULL;
+               }
+               break;
+
+       case AST_OP_EQ:
+       case AST_OP_NE:
+       case AST_OP_GT:
+       case AST_OP_LT:
+       case AST_OP_GE:
+       case AST_OP_LE:
+               lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
+               if (!lchild)
+                       return NULL;
+               rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_RIGHT);
+               if (!rchild) {
+                       filter_free_ir_recursive(lchild);
+                       return NULL;
+               }
+               break;
+
+       case AST_OP_AND:
+       case AST_OP_OR:
+               /*
+                * Both children considered as left, since we need to
+                * populate R0.
+                */
+               lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
+               if (!lchild)
+                       return NULL;
+               rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_LEFT);
+               if (!rchild) {
+                       filter_free_ir_recursive(lchild);
+                       return NULL;
+               }
+               break;
+       }
+
+       switch (node->u.op.type) {
+       case AST_OP_AND:
+               op = make_op_binary_logical_and(lchild, rchild, side);
+               break;
+       case AST_OP_OR:
+               op = make_op_binary_logical_or(lchild, rchild, side);
+               break;
+       case AST_OP_EQ:
+               op = make_op_binary_eq(lchild, rchild, side);
+               break;
+       case AST_OP_NE:
+               op = make_op_binary_ne(lchild, rchild, side);
+               break;
+       case AST_OP_GT:
+               op = make_op_binary_gt(lchild, rchild, side);
+               break;
+       case AST_OP_LT:
+               op = make_op_binary_lt(lchild, rchild, side);
+               break;
+       case AST_OP_GE:
+               op = make_op_binary_ge(lchild, rchild, side);
+               break;
+       case AST_OP_LE:
+               op = make_op_binary_le(lchild, rchild, side);
+               break;
+       case AST_OP_BIT_RSHIFT:
+               op = make_op_binary_bitwise_rshift(lchild, rchild, side);
+               break;
+       case AST_OP_BIT_LSHIFT:
+               op = make_op_binary_bitwise_lshift(lchild, rchild, side);
+               break;
+       case AST_OP_BIT_AND:
+               op = make_op_binary_bitwise_and(lchild, rchild, side);
+               break;
+       case AST_OP_BIT_OR:
+               op = make_op_binary_bitwise_or(lchild, rchild, side);
+               break;
+       case AST_OP_BIT_XOR:
+               op = make_op_binary_bitwise_xor(lchild, rchild, side);
+               break;
+       default:
+               break;
+       }
+
+       if (!op) {
+               filter_free_ir_recursive(rchild);
+               filter_free_ir_recursive(lchild);
+       }
+       return op;
+
+error_not_supported:
+       fprintf(stderr, "[error] %s: binary operation '%s' not supported\n",
+               __func__, op_str);
+       return NULL;
+}
+
+static
+struct ir_op *make_unary_op(struct filter_parser_ctx *ctx,
+               struct filter_node *node, enum ir_side side)
+{
+       switch (node->u.unary_op.type) {
+       case AST_UNARY_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown unary op type\n", __func__);
+               return NULL;
+
+       case AST_UNARY_PLUS:
+       {
+               struct ir_op *op, *child;
+
+               child = generate_ir_recursive(ctx, node->u.unary_op.child,
+                                       side);
+               if (!child)
+                       return NULL;
+               op = make_op_unary_plus(child, side);
+               if (!op) {
+                       filter_free_ir_recursive(child);
+                       return NULL;
+               }
+               return op;
+       }
+       case AST_UNARY_MINUS:
+       {
+               struct ir_op *op, *child;
+
+               child = generate_ir_recursive(ctx, node->u.unary_op.child,
+                                       side);
+               if (!child)
+                       return NULL;
+               op = make_op_unary_minus(child, side);
+               if (!op) {
+                       filter_free_ir_recursive(child);
+                       return NULL;
+               }
+               return op;
+       }
+       case AST_UNARY_NOT:
+       {
+               struct ir_op *op, *child;
+
+               child = generate_ir_recursive(ctx, node->u.unary_op.child,
+                                       side);
+               if (!child)
+                       return NULL;
+               op = make_op_unary_not(child, side);
+               if (!op) {
+                       filter_free_ir_recursive(child);
+                       return NULL;
+               }
+               return op;
+       }
+       case AST_UNARY_BIT_NOT:
+       {
+               struct ir_op *op, *child;
+
+               child = generate_ir_recursive(ctx, node->u.unary_op.child,
+                                       side);
+               if (!child)
+                       return NULL;
+               op = make_op_unary_bit_not(child, side);
+               if (!op) {
+                       filter_free_ir_recursive(child);
+                       return NULL;
+               }
+               return op;
+       }
+       }
+
+       return NULL;
+}
+
+static
+struct ir_op *generate_ir_recursive(struct filter_parser_ctx *ctx,
+               struct filter_node *node, enum ir_side side)
+{
+       switch (node->type) {
+       case NODE_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown node type\n", __func__);
+               return NULL;
+
+       case NODE_ROOT:
+       {
+               struct ir_op *op, *child;
+
+               child = generate_ir_recursive(ctx, node->u.root.child,
+                                       side);
+               if (!child)
+                       return NULL;
+               op = make_op_root(child, side);
+               if (!op) {
+                       filter_free_ir_recursive(child);
+                       return NULL;
+               }
+               return op;
+       }
+       case NODE_EXPRESSION:
+               return make_expression(ctx, node, side);
+       case NODE_OP:
+               return make_op(ctx, node, side);
+       case NODE_UNARY_OP:
+               return make_unary_op(ctx, node, side);
+       }
+       return 0;
+}
+
+LTTNG_HIDDEN
+void filter_ir_free(struct filter_parser_ctx *ctx)
+{
+       filter_free_ir_recursive(ctx->ir_root);
+       ctx->ir_root = NULL;
+}
+
+LTTNG_HIDDEN
+int filter_visitor_ir_generate(struct filter_parser_ctx *ctx)
+{
+       struct ir_op *op;
+
+       op = generate_ir_recursive(ctx, &ctx->ast->root, IR_LEFT);
+       if (!op) {
+               return -EINVAL;
+       }
+       ctx->ir_root = op;
+       return 0;
+}
diff --git a/src/common/filter/filter-visitor-ir-check-binary-comparator.c b/src/common/filter/filter-visitor-ir-check-binary-comparator.c
new file mode 100644 (file)
index 0000000..bcbb69e
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * filter-visitor-ir-check-binary-comparator.c
+ *
+ * LTTng filter IR check binary comparator
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include "filter-ast.h"
+#include "filter-parser.h"
+#include "filter-ir.h"
+
+static
+int check_bin_comparator(struct ir_op *node)
+{
+       switch (node->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
+               return -EINVAL;
+
+       case IR_OP_ROOT:
+               return check_bin_comparator(node->u.root.child);
+       case IR_OP_LOAD:
+               return 0;
+       case IR_OP_UNARY:
+               return check_bin_comparator(node->u.unary.child);
+       case IR_OP_BINARY:
+       {
+               int ret;
+
+               if (node->u.binary.left->data_type == IR_DATA_STRING
+                               || node->u.binary.right->data_type
+                                       == IR_DATA_STRING) {
+                       if (node->u.binary.type != AST_OP_EQ
+                                       && node->u.binary.type != AST_OP_NE) {
+                               fprintf(stderr, "[error] Only '==' and '!=' comparators are allowed for strings\n");
+                               return -EINVAL;
+                       }
+               }
+
+               ret = check_bin_comparator(node->u.binary.left);
+               if (ret)
+                       return ret;
+               return check_bin_comparator(node->u.binary.right);
+       }
+       case IR_OP_LOGICAL:
+       {
+               int ret;
+
+               ret = check_bin_comparator(node->u.logical.left);
+               if (ret)
+                       return ret;
+               return check_bin_comparator(node->u.logical.right);
+       }
+       }
+}
+
+int filter_visitor_ir_check_binary_comparator(struct filter_parser_ctx *ctx)
+{
+       return check_bin_comparator(ctx->ir_root);
+}
diff --git a/src/common/filter/filter-visitor-ir-check-binary-op-nesting.c b/src/common/filter/filter-visitor-ir-check-binary-op-nesting.c
new file mode 100644 (file)
index 0000000..04a5fbd
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * filter-visitor-ir-check-binary-op-nesting.c
+ *
+ * LTTng filter IR check binary op nesting
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include "filter-ast.h"
+#include "filter-parser.h"
+#include "filter-ir.h"
+
+#include <common/macros.h>
+
+static
+int check_bin_op_nesting_recursive(struct ir_op *node, int nesting)
+{
+       switch (node->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
+               return -EINVAL;
+
+       case IR_OP_ROOT:
+               return check_bin_op_nesting_recursive(node->u.root.child,
+                               nesting);
+       case IR_OP_LOAD:
+               return 0;
+       case IR_OP_UNARY:
+               return check_bin_op_nesting_recursive(node->u.unary.child,
+                               nesting);
+       case IR_OP_BINARY:
+       {
+               int ret;
+
+               ret = check_bin_op_nesting_recursive(node->u.binary.left,
+                               nesting + 1);
+               if (ret)
+                       return ret;
+               return check_bin_op_nesting_recursive(node->u.binary.right,
+                               nesting + 1);
+       }
+       case IR_OP_LOGICAL:
+       {
+               int ret;
+
+               ret = check_bin_op_nesting_recursive(node->u.logical.left,
+                               nesting);
+               if (ret)
+                       return ret;
+               return check_bin_op_nesting_recursive(node->u.logical.right,
+                               nesting);
+       }
+       }
+}
+
+LTTNG_HIDDEN
+int filter_visitor_ir_check_binary_op_nesting(struct filter_parser_ctx *ctx)
+{
+       return check_bin_op_nesting_recursive(ctx->ir_root, 0);
+}
diff --git a/src/common/filter/filter-visitor-ir-normalize-glob-patterns.c b/src/common/filter/filter-visitor-ir-normalize-glob-patterns.c
new file mode 100644 (file)
index 0000000..5e2778e
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * filter-visitor-ir-normalize-glob-patterns.c
+ *
+ * LTTng filter IR normalize string
+ *
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <common/macros.h>
+#include <common/string-utils/string-utils.h>
+
+#include "filter-ast.h"
+#include "filter-parser.h"
+#include "filter-ir.h"
+
+static
+int normalize_glob_patterns(struct ir_op *node)
+{
+       switch (node->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
+               return -EINVAL;
+
+       case IR_OP_ROOT:
+               return normalize_glob_patterns(node->u.root.child);
+       case IR_OP_LOAD:
+       {
+               if (node->data_type == IR_DATA_STRING) {
+                       enum ir_load_string_type type =
+                               node->u.load.u.string.type;
+                       if (type == IR_LOAD_STRING_TYPE_GLOB_STAR_END ||
+                                       type == IR_LOAD_STRING_TYPE_GLOB_STAR) {
+                               assert(node->u.load.u.string.value);
+                               strutils_normalize_star_glob_pattern(
+                                       node->u.load.u.string.value);
+                       }
+               }
+
+               return 0;
+       }
+       case IR_OP_UNARY:
+               return normalize_glob_patterns(node->u.unary.child);
+       case IR_OP_BINARY:
+       {
+               int ret = normalize_glob_patterns(node->u.binary.left);
+
+               if (ret)
+                       return ret;
+               return normalize_glob_patterns(node->u.binary.right);
+       }
+       case IR_OP_LOGICAL:
+       {
+               int ret;
+
+               ret = normalize_glob_patterns(node->u.logical.left);
+               if (ret)
+                       return ret;
+               return normalize_glob_patterns(node->u.logical.right);
+       }
+       }
+}
+
+/*
+ * This function normalizes all the globbing literal strings with
+ * utils_normalize_glob_pattern(). See the documentation of
+ * utils_normalize_glob_pattern() for more details.
+ */
+LTTNG_HIDDEN
+int filter_visitor_ir_normalize_glob_patterns(struct filter_parser_ctx *ctx)
+{
+       return normalize_glob_patterns(ctx->ir_root);
+}
diff --git a/src/common/filter/filter-visitor-ir-validate-globbing.c b/src/common/filter/filter-visitor-ir-validate-globbing.c
new file mode 100644 (file)
index 0000000..3e749a4
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * filter-visitor-ir-validate-globbing.c
+ *
+ * LTTng filter IR validate globbing
+ *
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <common/macros.h>
+
+#include "filter-ast.h"
+#include "filter-parser.h"
+#include "filter-ir.h"
+
+static
+int validate_globbing(struct ir_op *node)
+{
+       int ret;
+
+       switch (node->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
+               return -EINVAL;
+
+       case IR_OP_ROOT:
+               return validate_globbing(node->u.root.child);
+       case IR_OP_LOAD:
+               return 0;
+       case IR_OP_UNARY:
+               return validate_globbing(node->u.unary.child);
+       case IR_OP_BINARY:
+       {
+               struct ir_op *left = node->u.binary.left;
+               struct ir_op *right = node->u.binary.right;
+
+               if (left->op == IR_OP_LOAD && right->op == IR_OP_LOAD &&
+                               left->data_type == IR_DATA_STRING &&
+                               right->data_type == IR_DATA_STRING) {
+                       /* Test 1. */
+                       if (left->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR &&
+                                       right->u.load.u.string.type != IR_LOAD_STRING_TYPE_PLAIN) {
+                               fprintf(stderr, "[error] Cannot compare two globbing patterns\n");
+                               return -1;
+                       }
+
+                       if (right->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR &&
+                                       left->u.load.u.string.type != IR_LOAD_STRING_TYPE_PLAIN) {
+                               fprintf(stderr, "[error] Cannot compare two globbing patterns\n");
+                               return -1;
+                       }
+               }
+
+               if ((left->op == IR_OP_LOAD && left->data_type == IR_DATA_STRING) ||
+                               (right->op == IR_OP_LOAD && right->data_type == IR_DATA_STRING)) {
+                       if ((left->op == IR_OP_LOAD && left->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR) ||
+                                       (right->op == IR_OP_LOAD && right->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR)) {
+                               /* Test 2. */
+                               if (node->u.binary.type != AST_OP_EQ &&
+                                               node->u.binary.type != AST_OP_NE) {
+                                       fprintf(stderr, "[error] Only the `==` and `!=` operators are allowed with a globbing pattern\n");
+                                       return -1;
+                               }
+                       }
+               }
+
+               ret = validate_globbing(left);
+               if (ret) {
+                       return ret;
+               }
+
+               return validate_globbing(right);
+       }
+       case IR_OP_LOGICAL:
+               ret = validate_globbing(node->u.logical.left);
+               if (ret)
+                       return ret;
+               return validate_globbing(node->u.logical.right);
+       }
+}
+
+/*
+ * This function recursively validates that:
+ *
+ * 1. When there's a binary operation between two literal strings,
+ *    if one of them has the IR_LOAD_STRING_TYPE_GLOB_STAR type,
+ *    the other one has the IR_LOAD_STRING_TYPE_PLAIN type.
+ *
+ *    In other words, you cannot compare two globbing patterns, except
+ *    for two globbing patterns with only a star at the end for backward
+ *    compatibility reasons.
+ *
+ * 2. When there's a binary operation between two literal strings, if
+ *    one of them is a (full) star globbing pattern, the binary
+ *    operation is either == or !=.
+ */
+LTTNG_HIDDEN
+int filter_visitor_ir_validate_globbing(struct filter_parser_ctx *ctx)
+{
+       return validate_globbing(ctx->ir_root);
+}
diff --git a/src/common/filter/filter-visitor-ir-validate-string.c b/src/common/filter/filter-visitor-ir-validate-string.c
new file mode 100644 (file)
index 0000000..1df83b0
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * filter-visitor-ir-validate-string.c
+ *
+ * LTTng filter IR validate string
+ *
+ * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <common/macros.h>
+
+#include "filter-ast.h"
+#include "filter-parser.h"
+#include "filter-ir.h"
+
+enum parse_char_result {
+       PARSE_CHAR_UNKNOWN = -2,
+       PARSE_CHAR_WILDCARD = -1,
+       PARSE_CHAR_NORMAL = 0,
+};
+
+static
+enum parse_char_result parse_char(const char **p)
+{
+       switch (**p) {
+       case '\\':
+               (*p)++;
+               switch (**p) {
+               case '\\':
+               case '*':
+                       return PARSE_CHAR_NORMAL;
+               default:
+                       return PARSE_CHAR_UNKNOWN;
+               }
+       case '*':
+               return PARSE_CHAR_WILDCARD;
+       default:
+               return PARSE_CHAR_NORMAL;
+       }
+}
+
+static
+int validate_string(struct ir_op *node)
+{
+       switch (node->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
+               return -EINVAL;
+
+       case IR_OP_ROOT:
+               return validate_string(node->u.root.child);
+       case IR_OP_LOAD:
+       {
+               int ret = 0;
+
+               if (node->data_type == IR_DATA_STRING) {
+                       const char *str;
+
+                       assert(node->u.load.u.string.value);
+                       str = node->u.load.u.string.value;
+
+                       for (;;) {
+                               enum parse_char_result res;
+
+                               if (!(*str)) {
+                                       break;
+                               }
+
+                               res = parse_char(&str);
+                               str++;
+
+                               switch (res) {
+                               case PARSE_CHAR_UNKNOWN:
+                                       ret = -EINVAL;
+                                       fprintf(stderr,
+                                               "Unsupported escape character detected.\n");
+                                       goto end_load;
+                               case PARSE_CHAR_NORMAL:
+                               default:
+                                       break;
+                               }
+                       }
+               }
+end_load:
+               return ret;
+       }
+       case IR_OP_UNARY:
+               return validate_string(node->u.unary.child);
+       case IR_OP_BINARY:
+       {
+               int ret = validate_string(node->u.binary.left);
+
+               if (ret)
+                       return ret;
+               return validate_string(node->u.binary.right);
+       }
+       case IR_OP_LOGICAL:
+       {
+               int ret;
+
+               ret = validate_string(node->u.logical.left);
+               if (ret)
+                       return ret;
+               return validate_string(node->u.logical.right);
+       }
+       }
+}
+
+LTTNG_HIDDEN
+int filter_visitor_ir_validate_string(struct filter_parser_ctx *ctx)
+{
+       return validate_string(ctx->ir_root);
+}
diff --git a/src/common/filter/filter-visitor-xml.c b/src/common/filter/filter-visitor-xml.c
new file mode 100644 (file)
index 0000000..d5ff0c1
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * filter-visitor-xml.c
+ *
+ * LTTng filter XML pretty printer visitor
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include "filter-ast.h"
+#include "filter-parser.h"
+
+#include <common/macros.h>
+
+#define fprintf_dbg(fd, fmt, args...)  fprintf(fd, "%s: " fmt, __func__, ## args)
+
+static
+int recursive_visit_print(struct filter_node *node, FILE *stream, int indent);
+
+static
+void print_tabs(FILE *fd, int depth)
+{
+       int i;
+
+       for (i = 0; i < depth; i++)
+               fprintf(fd, "\t");
+}
+
+static
+int recursive_visit_print_expression(struct filter_node *node,
+               FILE *stream, int indent)
+{
+       struct filter_node *iter_node;
+
+       if (!node) {
+               fprintf(stderr, "[error] %s: NULL child\n", __func__);
+               return -EINVAL;
+       }
+       switch (node->u.expression.type) {
+       case AST_EXP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown expression\n", __func__);
+               return -EINVAL;
+       case AST_EXP_STRING:
+               print_tabs(stream, indent);
+               fprintf(stream, "<string value=\"%s\"/>\n",
+                       node->u.expression.u.string);
+               break;
+       case AST_EXP_CONSTANT:
+               print_tabs(stream, indent);
+               fprintf(stream, "<constant value=\"%" PRIu64 "\"/>\n",
+                       node->u.expression.u.constant);
+               break;
+       case AST_EXP_FLOAT_CONSTANT:
+               print_tabs(stream, indent);
+               fprintf(stream, "<float_constant value=\"%lg\"/>\n",
+                       node->u.expression.u.float_constant);
+               break;
+       case AST_EXP_IDENTIFIER:                /* fall-through */
+       case AST_EXP_GLOBAL_IDENTIFIER:
+               print_tabs(stream, indent);
+               fprintf(stream, "<%s value=\"%s\"/>\n",
+                       node->u.expression.type == AST_EXP_IDENTIFIER ?
+                               "identifier" : "global_identifier",
+                       node->u.expression.u.identifier);
+               iter_node = node->u.expression.next;
+               while (iter_node) {
+                       print_tabs(stream, indent);
+                       fprintf(stream, "<bracket>\n");
+                       if (recursive_visit_print_expression(iter_node,
+                                       stream, indent + 1)) {
+                               return -EINVAL;
+                       }
+                       print_tabs(stream, indent);
+                       fprintf(stream, "</bracket>\n");
+                       iter_node = iter_node->u.expression.next;
+
+               }
+               break;
+       case AST_EXP_NESTED:
+               return recursive_visit_print(node->u.expression.u.child,
+                               stream, indent + 1);
+       }
+       return 0;
+}
+
+
+static
+int recursive_visit_print(struct filter_node *node, FILE *stream, int indent)
+{
+       int ret;
+
+       if (!node) {
+               fprintf(stderr, "[error] %s: NULL child\n", __func__);
+               return -EINVAL;
+       }
+       switch (node->type) {
+       case NODE_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown node type\n", __func__);
+               return -EINVAL;
+       case NODE_ROOT:
+               print_tabs(stream, indent);
+               fprintf(stream, "<root>\n");
+               ret = recursive_visit_print(node->u.root.child, stream,
+                                       indent + 1);
+               print_tabs(stream, indent);
+               fprintf(stream, "</root>\n");
+               return ret;
+       case NODE_EXPRESSION:
+               print_tabs(stream, indent);
+               fprintf(stream, "<expression>\n");
+               ret = recursive_visit_print_expression(node, stream,
+                                       indent + 1);
+               print_tabs(stream, indent);
+               fprintf(stream, "</expression>\n");
+               return ret;
+       case NODE_OP:
+               print_tabs(stream, indent);
+               fprintf(stream, "<op type=");
+               switch (node->u.op.type) {
+               case AST_OP_UNKNOWN:
+               default:
+                       fprintf(stderr, "[error] %s: unknown op\n", __func__);
+                       return -EINVAL;
+               case AST_OP_MUL:
+                       fprintf(stream, "\"*\"");
+                       break;
+               case AST_OP_DIV:
+                       fprintf(stream, "\"/\"");
+                       break;
+               case AST_OP_MOD:
+                       fprintf(stream, "\"%%\"");
+                       break;
+               case AST_OP_PLUS:
+                       fprintf(stream, "\"+\"");
+                       break;
+               case AST_OP_MINUS:
+                       fprintf(stream, "\"-\"");
+                       break;
+               case AST_OP_BIT_RSHIFT:
+                       fprintf(stream, "\">>\"");
+                       break;
+               case AST_OP_BIT_LSHIFT:
+                       fprintf(stream, "\"<<\"");
+                       break;
+               case AST_OP_AND:
+                       fprintf(stream, "\"&&\"");
+                       break;
+               case AST_OP_OR:
+                       fprintf(stream, "\"||\"");
+                       break;
+               case AST_OP_BIT_AND:
+                       fprintf(stream, "\"&\"");
+                       break;
+               case AST_OP_BIT_OR:
+                       fprintf(stream, "\"|\"");
+                       break;
+               case AST_OP_BIT_XOR:
+                       fprintf(stream, "\"^\"");
+                       break;
+
+               case AST_OP_EQ:
+                       fprintf(stream, "\"==\"");
+                       break;
+               case AST_OP_NE:
+                       fprintf(stream, "\"!=\"");
+                       break;
+               case AST_OP_GT:
+                       fprintf(stream, "\">\"");
+                       break;
+               case AST_OP_LT:
+                       fprintf(stream, "\"<\"");
+                       break;
+               case AST_OP_GE:
+                       fprintf(stream, "\">=\"");
+                       break;
+               case AST_OP_LE:
+                       fprintf(stream, "\"<=\"");
+                       break;
+               }
+               fprintf(stream, ">\n");
+               ret = recursive_visit_print(node->u.op.lchild,
+                                       stream, indent + 1);
+               if (ret)
+                       return ret;
+               ret = recursive_visit_print(node->u.op.rchild,
+                                       stream, indent + 1);
+               if (ret)
+                       return ret;
+               print_tabs(stream, indent);
+               fprintf(stream, "</op>\n");
+               return ret;
+       case NODE_UNARY_OP:
+               print_tabs(stream, indent);
+               fprintf(stream, "<unary_op type=");
+               switch (node->u.unary_op.type) {
+               case AST_UNARY_UNKNOWN:
+               default:
+                       fprintf(stderr, "[error] %s: unknown unary_op\n", __func__);
+                       return -EINVAL;
+               case AST_UNARY_PLUS:
+                       fprintf(stream, "\"+\"");
+                       break;
+               case AST_UNARY_MINUS:
+                       fprintf(stream, "\"-\"");
+                       break;
+               case AST_UNARY_NOT:
+                       fprintf(stream, "\"!\"");
+                       break;
+               case AST_UNARY_BIT_NOT:
+                       fprintf(stream, "\"~\"");
+                       break;
+               }
+               fprintf(stream, ">\n");
+               ret = recursive_visit_print(node->u.unary_op.child,
+                                       stream, indent + 1);
+               print_tabs(stream, indent);
+               fprintf(stream, "</unary_op>\n");
+               return ret;
+       }
+       return 0;
+}
+
+LTTNG_HIDDEN
+int filter_visitor_print_xml(struct filter_parser_ctx *ctx, FILE *stream,
+                       int indent)
+{
+       return recursive_visit_print(&ctx->ast->root, stream, indent);
+}
diff --git a/src/common/filter/memstream.h b/src/common/filter/memstream.h
new file mode 100644 (file)
index 0000000..cd246ee
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2012 (C) Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#ifndef _LTTNG_CTL_MEMSTREAM_H
+#define _LTTNG_CTL_MEMSTREAM_H
+
+#ifdef LTTNG_HAVE_FMEMOPEN
+#include <stdio.h>
+
+static inline
+FILE *lttng_fmemopen(void *buf, size_t size, const char *mode)
+{
+       return fmemopen(buf, size, mode);
+}
+
+#else /* LTTNG_HAVE_FMEMOPEN */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * Fallback for systems which don't have fmemopen. Copy buffer to a
+ * temporary file, and use that file as FILE * input.
+ */
+static inline
+FILE *lttng_fmemopen(void *buf, size_t size, const char *mode)
+{
+       char tmpname[PATH_MAX];
+       size_t len;
+       FILE *fp;
+       int ret;
+
+       /*
+        * Support reading only.
+        */
+       if (strcmp(mode, "rb") != 0) {
+               return NULL;
+       }
+       strncpy(tmpname, "/tmp/lttng-tmp-XXXXXX", PATH_MAX);
+       ret = mkstemp(tmpname);
+       if (ret < 0) {
+               return NULL;
+       }
+       /*
+        * We need to write to the file.
+        */
+       fp = fdopen(ret, "w+");
+       if (!fp) {
+               goto error_unlink;
+       }
+       /* Copy the entire buffer to the file */
+       len = fwrite(buf, sizeof(char), size, fp);
+       if (len != size) {
+               goto error_close;
+       }
+       ret = fseek(fp, 0L, SEEK_SET);
+       if (ret < 0) {
+               PERROR("fseek");
+               goto error_close;
+       }
+       /* We keep the handle open, but can unlink the file on the VFS. */
+       ret = unlink(tmpname);
+       if (ret < 0) {
+               PERROR("unlink");
+       }
+       return fp;
+
+error_close:
+       ret = fclose(fp);
+       if (ret < 0) {
+               PERROR("close");
+       }
+error_unlink:
+       ret = unlink(tmpname);
+       if (ret < 0) {
+               PERROR("unlink");
+       }
+       return NULL;
+}
+
+#endif /* LTTNG_HAVE_FMEMOPEN */
+
+#endif /* _LTTNG_CTL_MEMSTREAM_H */
index 1bee05f0c8b690a33b12d0ca8494cd906c89c7b5..8c271f5efd0a937c98ecfb6fa2ff98b0493018d7 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 # SPDX-License-Identifier: GPL-2.0-only
 
-SUBDIRS = filter
+SUBDIRS =
 
 AM_CPPFLAGS += -I$(srcdir) -I$(builddir)
 
 
 AM_CPPFLAGS += -I$(srcdir) -I$(builddir)
 
@@ -16,8 +16,7 @@ liblttng_ctl_la_LDFLAGS = \
 
 liblttng_ctl_la_LIBADD = \
                $(top_builddir)/src/common/sessiond-comm/libsessiond-comm.la \
 
 liblttng_ctl_la_LIBADD = \
                $(top_builddir)/src/common/sessiond-comm/libsessiond-comm.la \
-               $(top_builddir)/src/common/libcommon.la \
-               $(top_builddir)/src/lib/lttng-ctl/filter/libfilter.la
+               $(top_builddir)/src/common/libcommon.la
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = lttng-ctl.pc
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = lttng-ctl.pc
diff --git a/src/lib/lttng-ctl/filter/Makefile.am b/src/lib/lttng-ctl/filter/Makefile.am
deleted file mode 100644 (file)
index cac4cb1..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-
-AM_CPPFLAGS += -I$(srcdir) -I$(builddir)
-
-noinst_PROGRAMS = filter-grammar-test
-noinst_LTLIBRARIES = libfilter.la
-noinst_HEADERS = filter-ast.h \
-               filter-symbols.h
-
-BUILT_SOURCES = filter-parser.h
-
-libfilter_la_SOURCES = \
-       filter-parser.y filter-lexer.l \
-       filter-visitor-xml.c \
-       filter-visitor-generate-ir.c \
-       filter-visitor-ir-check-binary-op-nesting.c \
-       filter-visitor-ir-validate-string.c \
-       filter-visitor-ir-validate-globbing.c \
-       filter-visitor-ir-normalize-glob-patterns.c \
-       filter-visitor-generate-bytecode.c \
-       filter-ast.h \
-       filter-bytecode.h \
-       filter-ir.h \
-       memstream.h
-libfilter_la_CFLAGS = -include filter-symbols.h $(AM_CFLAGS)
-libfilter_la_LIBADD = $(top_builddir)/src/common/string-utils/libstring-utils.la
-
-AM_YFLAGS = -t -d -v -Wno-yacc
-
-# start with empty files to clean
-CLEANFILES =
-
-if HAVE_BISON
-# we have bison: we can clean the generated parser files
-CLEANFILES += filter-parser.c filter-parser.h filter-parser.output
-else # HAVE_BISON
-# create target used to stop the build if we want to build the parser,
-# but we don't have the necessary tool to do so
-ERR_MSG = "Error: Cannot build target because bison is missing."
-ERR_MSG += "Make sure bison is installed and run the configure script again."
-
-filter-parser.c filter-parser.h: filter-parser.y
-       @echo $(ERR_MSG)
-       @false
-
-all-local: filter-parser.c filter-parser.h
-endif # HAVE_BISON
-
-if HAVE_FLEX
-# we have flex: we can clean the generated lexer files
-CLEANFILES += filter-lexer.c
-else # HAVE_FLEX
-# create target used to stop the build if we want to build the lexer,
-# but we don't have the necessary tool to do so
-ERR_MSG = "Error: Cannot build target because flex is missing."
-ERR_MSG += "Make sure flex is installed and run the configure script again."
-
-filter-lexer.c: filter-lexer.l
-       @echo $(ERR_MSG)
-       @false
-
-all-local: filter-lexer.c
-endif # HAVE_FLEX
-
-filter_grammar_test_SOURCES = filter-grammar-test.c
-filter_grammar_test_LDADD = libfilter.la
diff --git a/src/lib/lttng-ctl/filter/filter-ast.h b/src/lib/lttng-ctl/filter/filter-ast.h
deleted file mode 100644 (file)
index 926d8dd..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-#ifndef _FILTER_AST_H
-#define _FILTER_AST_H
-
-/*
- * filter-ast.h
- *
- * LTTng filter AST
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-/*
- * Note: filter-ast.h should be included before filter-parser.h.
- */
-
-#include <urcu/list.h>
-#include <stdint.h>
-
-#define printf_debug(fmt, args...)                                     \
-       do {                                                            \
-               if (filter_parser_debug)                                \
-                       fprintf(stdout, "[debug] " fmt, ## args);       \
-       } while (0)
-
-// the parameter name (of the reentrant 'yyparse' function)
-// data is a pointer to a 'SParserParam' structure
-//#define YYPARSE_PARAM        parser_ctx
-
-#ifndef YY_TYPEDEF_YY_SCANNER_T
-#define YY_TYPEDEF_YY_SCANNER_T
-typedef void* yyscan_t;
-#endif
-
-extern int filter_parser_debug;
-
-struct filter_node;
-struct filter_parser;
-
-enum node_type {
-       NODE_UNKNOWN = 0,
-       NODE_ROOT,
-
-       NODE_EXPRESSION,
-       NODE_OP,
-       NODE_UNARY_OP,
-
-       NR_NODE_TYPES,
-};
-
-enum op_type {
-       AST_OP_UNKNOWN = 0,
-       AST_OP_MUL,
-       AST_OP_DIV,
-       AST_OP_MOD,
-       AST_OP_PLUS,
-       AST_OP_MINUS,
-       AST_OP_BIT_RSHIFT,
-       AST_OP_BIT_LSHIFT,
-       AST_OP_AND,
-       AST_OP_OR,
-       AST_OP_BIT_AND,
-       AST_OP_BIT_OR,
-       AST_OP_BIT_XOR,
-
-       AST_OP_EQ,
-       AST_OP_NE,
-       AST_OP_GT,
-       AST_OP_LT,
-       AST_OP_GE,
-       AST_OP_LE,
-};
-
-enum unary_op_type {
-       AST_UNARY_UNKNOWN = 0,
-       AST_UNARY_PLUS,
-       AST_UNARY_MINUS,
-       AST_UNARY_NOT,
-       AST_UNARY_BIT_NOT,
-};
-
-enum ast_link_type {
-       AST_LINK_UNKNOWN = 0,
-       AST_LINK_DOT,
-       AST_LINK_RARROW,
-       AST_LINK_BRACKET,
-};
-
-struct filter_node {
-       /*
-        * Parent node is only set on demand by specific visitor.
-        */
-       struct filter_node *parent;
-       struct cds_list_head gc;
-
-       enum node_type type;
-       union {
-               struct {
-               } unknown;
-               struct {
-                       struct filter_node *child;
-               } root;
-               struct {
-                       enum {
-                               AST_EXP_UNKNOWN = 0,
-                               AST_EXP_STRING,
-                               AST_EXP_CONSTANT,
-                               AST_EXP_FLOAT_CONSTANT,
-                               AST_EXP_IDENTIFIER,
-                               AST_EXP_GLOBAL_IDENTIFIER,
-                               AST_EXP_NESTED,
-                       } type;
-                       enum ast_link_type post_op;     /* reverse */
-                       enum ast_link_type pre_op;      /* forward */
-                       union {
-                               const char *string;
-                               uint64_t constant;
-                               double float_constant;
-                               const char *identifier;
-                               /*
-                                * child can be nested.
-                                */
-                               struct filter_node *child;
-                       } u;
-                       /* prev: backward dot/arrow chain (postfix expression) */
-                       struct filter_node *prev;
-                       /* next: forward dot/arrow chain, generated by a visitor. */
-                       struct filter_node *next;
-                       /* next_bracket: linked bracket chain (prefix expression) */
-                       struct filter_node *next_bracket;
-               } expression;
-               struct {
-                       enum op_type type;
-                       struct filter_node *lchild;
-                       struct filter_node *rchild;
-               } op;
-               struct {
-                       enum unary_op_type type;
-                       struct filter_node *child;
-               } unary_op;
-       } u;
-};
-
-struct filter_ast {
-       struct filter_node root;
-       struct cds_list_head allocated_nodes;
-};
-
-const char *node_type(struct filter_node *node);
-
-struct ir_op;
-
-struct filter_parser_ctx {
-       yyscan_t scanner;
-       struct filter_ast *ast;
-       struct cds_list_head allocated_strings;
-       struct ir_op *ir_root;
-       struct lttng_filter_bytecode_alloc *bytecode;
-       struct lttng_filter_bytecode_alloc *bytecode_reloc;
-};
-
-struct filter_parser_ctx *filter_parser_ctx_alloc(FILE *input);
-void filter_parser_ctx_free(struct filter_parser_ctx *parser_ctx);
-int filter_parser_ctx_append_ast(struct filter_parser_ctx *parser_ctx);
-
-static inline
-struct filter_ast *filter_parser_get_ast(struct filter_parser_ctx *parser_ctx)
-{
-       return parser_ctx->ast;
-}
-
-int filter_visitor_print_xml(struct filter_parser_ctx *ctx, FILE *stream,
-                       int indent);
-int filter_visitor_ir_generate(struct filter_parser_ctx *ctx);
-void filter_ir_free(struct filter_parser_ctx *ctx);
-int filter_visitor_bytecode_generate(struct filter_parser_ctx *ctx);
-void filter_bytecode_free(struct filter_parser_ctx *ctx);
-int filter_visitor_ir_check_binary_op_nesting(struct filter_parser_ctx *ctx);
-int filter_visitor_ir_check_binary_comparator(struct filter_parser_ctx *ctx);
-int filter_visitor_ir_validate_string(struct filter_parser_ctx *ctx);
-int filter_visitor_ir_normalize_glob_patterns(struct filter_parser_ctx *ctx);
-int filter_visitor_ir_validate_globbing(struct filter_parser_ctx *ctx);
-
-#endif /* _FILTER_AST_H */
diff --git a/src/lib/lttng-ctl/filter/filter-bytecode.h b/src/lib/lttng-ctl/filter/filter-bytecode.h
deleted file mode 100644 (file)
index 053bb08..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-#ifndef _FILTER_BYTECODE_H
-#define _FILTER_BYTECODE_H
-
-/*
- * filter-bytecode.h
- *
- * LTTng filter bytecode
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/macros.h>
-
-#include "filter-ast.h"
-
-/*
- * offsets are absolute from start of bytecode.
- */
-
-struct field_ref {
-       /* Initially, symbol offset. After link, field offset. */
-       uint16_t offset;
-} LTTNG_PACKED;
-
-struct get_symbol {
-       /* Symbol offset. */
-       uint16_t offset;
-} LTTNG_PACKED;
-
-struct get_index_u16 {
-       uint16_t index;
-} LTTNG_PACKED;
-
-struct get_index_u64 {
-       uint64_t index;
-} LTTNG_PACKED;
-
-struct literal_numeric {
-       int64_t v;
-} LTTNG_PACKED;
-
-struct literal_double {
-       double v;
-} LTTNG_PACKED;
-
-struct literal_string {
-       char string[0];
-} LTTNG_PACKED;
-
-enum filter_op {
-       FILTER_OP_UNKNOWN                       = 0,
-
-       FILTER_OP_RETURN                        = 1,
-
-       /* binary */
-       FILTER_OP_MUL                           = 2,
-       FILTER_OP_DIV                           = 3,
-       FILTER_OP_MOD                           = 4,
-       FILTER_OP_PLUS                          = 5,
-       FILTER_OP_MINUS                         = 6,
-       FILTER_OP_BIT_RSHIFT                    = 7,
-       FILTER_OP_BIT_LSHIFT                    = 8,
-       FILTER_OP_BIT_AND                       = 9,
-       FILTER_OP_BIT_OR                        = 10,
-       FILTER_OP_BIT_XOR                       = 11,
-
-       /* binary comparators */
-       FILTER_OP_EQ                            = 12,
-       FILTER_OP_NE                            = 13,
-       FILTER_OP_GT                            = 14,
-       FILTER_OP_LT                            = 15,
-       FILTER_OP_GE                            = 16,
-       FILTER_OP_LE                            = 17,
-
-       /* string binary comparator: apply to  */
-       FILTER_OP_EQ_STRING                     = 18,
-       FILTER_OP_NE_STRING                     = 19,
-       FILTER_OP_GT_STRING                     = 20,
-       FILTER_OP_LT_STRING                     = 21,
-       FILTER_OP_GE_STRING                     = 22,
-       FILTER_OP_LE_STRING                     = 23,
-
-       /* s64 binary comparator */
-       FILTER_OP_EQ_S64                        = 24,
-       FILTER_OP_NE_S64                        = 25,
-       FILTER_OP_GT_S64                        = 26,
-       FILTER_OP_LT_S64                        = 27,
-       FILTER_OP_GE_S64                        = 28,
-       FILTER_OP_LE_S64                        = 29,
-
-       /* double binary comparator */
-       FILTER_OP_EQ_DOUBLE                     = 30,
-       FILTER_OP_NE_DOUBLE                     = 31,
-       FILTER_OP_GT_DOUBLE                     = 32,
-       FILTER_OP_LT_DOUBLE                     = 33,
-       FILTER_OP_GE_DOUBLE                     = 34,
-       FILTER_OP_LE_DOUBLE                     = 35,
-
-       /* Mixed S64-double binary comparators */
-       FILTER_OP_EQ_DOUBLE_S64                 = 36,
-       FILTER_OP_NE_DOUBLE_S64                 = 37,
-       FILTER_OP_GT_DOUBLE_S64                 = 38,
-       FILTER_OP_LT_DOUBLE_S64                 = 39,
-       FILTER_OP_GE_DOUBLE_S64                 = 40,
-       FILTER_OP_LE_DOUBLE_S64                 = 41,
-
-       FILTER_OP_EQ_S64_DOUBLE                 = 42,
-       FILTER_OP_NE_S64_DOUBLE                 = 43,
-       FILTER_OP_GT_S64_DOUBLE                 = 44,
-       FILTER_OP_LT_S64_DOUBLE                 = 45,
-       FILTER_OP_GE_S64_DOUBLE                 = 46,
-       FILTER_OP_LE_S64_DOUBLE                 = 47,
-
-       /* unary */
-       FILTER_OP_UNARY_PLUS                    = 48,
-       FILTER_OP_UNARY_MINUS                   = 49,
-       FILTER_OP_UNARY_NOT                     = 50,
-       FILTER_OP_UNARY_PLUS_S64                = 51,
-       FILTER_OP_UNARY_MINUS_S64               = 52,
-       FILTER_OP_UNARY_NOT_S64                 = 53,
-       FILTER_OP_UNARY_PLUS_DOUBLE             = 54,
-       FILTER_OP_UNARY_MINUS_DOUBLE            = 55,
-       FILTER_OP_UNARY_NOT_DOUBLE              = 56,
-
-       /* logical */
-       FILTER_OP_AND                           = 57,
-       FILTER_OP_OR                            = 58,
-
-       /* load field ref */
-       FILTER_OP_LOAD_FIELD_REF                = 59,
-       FILTER_OP_LOAD_FIELD_REF_STRING         = 60,
-       FILTER_OP_LOAD_FIELD_REF_SEQUENCE       = 61,
-       FILTER_OP_LOAD_FIELD_REF_S64            = 62,
-       FILTER_OP_LOAD_FIELD_REF_DOUBLE         = 63,
-
-       /* load immediate from operand */
-       FILTER_OP_LOAD_STRING                   = 64,
-       FILTER_OP_LOAD_S64                      = 65,
-       FILTER_OP_LOAD_DOUBLE                   = 66,
-
-       /* cast */
-       FILTER_OP_CAST_TO_S64                   = 67,
-       FILTER_OP_CAST_DOUBLE_TO_S64            = 68,
-       FILTER_OP_CAST_NOP                      = 69,
-
-       /* get context ref */
-       FILTER_OP_GET_CONTEXT_REF               = 70,
-       FILTER_OP_GET_CONTEXT_REF_STRING        = 71,
-       FILTER_OP_GET_CONTEXT_REF_S64           = 72,
-       FILTER_OP_GET_CONTEXT_REF_DOUBLE        = 73,
-
-       /* load userspace field ref */
-       FILTER_OP_LOAD_FIELD_REF_USER_STRING    = 74,
-       FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE  = 75,
-
-       /*
-        * load immediate star globbing pattern (literal string)
-        * from immediate
-        */
-       FILTER_OP_LOAD_STAR_GLOB_STRING         = 76,
-
-       /* globbing pattern binary operator: apply to */
-       FILTER_OP_EQ_STAR_GLOB_STRING           = 77,
-       FILTER_OP_NE_STAR_GLOB_STRING           = 78,
-
-       /*
-        * Instructions for recursive traversal through composed types.
-        */
-       FILTER_OP_GET_CONTEXT_ROOT              = 79,
-       FILTER_OP_GET_APP_CONTEXT_ROOT          = 80,
-       FILTER_OP_GET_PAYLOAD_ROOT              = 81,
-
-       FILTER_OP_GET_SYMBOL                    = 82,
-       FILTER_OP_GET_SYMBOL_FIELD              = 83,
-       FILTER_OP_GET_INDEX_U16                 = 84,
-       FILTER_OP_GET_INDEX_U64                 = 85,
-
-       FILTER_OP_LOAD_FIELD                    = 86,
-       FILTER_OP_LOAD_FIELD_S8                 = 87,
-       FILTER_OP_LOAD_FIELD_S16                = 88,
-       FILTER_OP_LOAD_FIELD_S32                = 89,
-       FILTER_OP_LOAD_FIELD_S64                = 90,
-       FILTER_OP_LOAD_FIELD_U8                 = 91,
-       FILTER_OP_LOAD_FIELD_U16                = 92,
-       FILTER_OP_LOAD_FIELD_U32                = 93,
-       FILTER_OP_LOAD_FIELD_U64                = 94,
-       FILTER_OP_LOAD_FIELD_STRING             = 95,
-       FILTER_OP_LOAD_FIELD_SEQUENCE           = 96,
-       FILTER_OP_LOAD_FIELD_DOUBLE             = 97,
-
-       FILTER_OP_UNARY_BIT_NOT                 = 98,
-
-       FILTER_OP_RETURN_S64                    = 99,
-
-       NR_FILTER_OPS,
-};
-
-typedef uint8_t filter_opcode_t;
-
-struct load_op {
-       filter_opcode_t op;
-       char data[0];
-       /* data to load. Size known by enum filter_opcode and null-term char. */
-} LTTNG_PACKED;
-
-struct binary_op {
-       filter_opcode_t op;
-} LTTNG_PACKED;
-
-struct unary_op {
-       filter_opcode_t op;
-} LTTNG_PACKED;
-
-/* skip_offset is absolute from start of bytecode */
-struct logical_op {
-       filter_opcode_t op;
-       uint16_t skip_offset;   /* bytecode insn, if skip second test */
-} LTTNG_PACKED;
-
-struct cast_op {
-       filter_opcode_t op;
-} LTTNG_PACKED;
-
-struct return_op {
-       filter_opcode_t op;
-} LTTNG_PACKED;
-
-struct lttng_filter_bytecode_alloc {
-       uint32_t alloc_len;
-       struct lttng_filter_bytecode b;
-};
-
-static inline
-unsigned int bytecode_get_len(struct lttng_filter_bytecode *bytecode)
-{
-       return bytecode->len;
-}
-
-#endif /* _FILTER_BYTECODE_H */
diff --git a/src/lib/lttng-ctl/filter/filter-grammar-test.c b/src/lib/lttng-ctl/filter/filter-grammar-test.c
deleted file mode 100644 (file)
index 70656e1..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * filter-grammar-test.c
- *
- * LTTng filter grammar test
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-bytecode.h"
-
-int main(int argc, char **argv)
-{
-       struct filter_parser_ctx *ctx;
-       int ret;
-       int print_xml = 0, generate_ir = 0, generate_bytecode = 0,
-               print_bytecode = 0;
-       int i;
-
-       for (i = 1; i < argc; i++) {
-               if (strcmp(argv[i], "-p") == 0)
-                       print_xml = 1;
-               else if (strcmp(argv[i], "-i") == 0)
-                       generate_ir = 1;
-               else if (strcmp(argv[i], "-b") == 0)
-                       generate_bytecode = 1;
-               else if (strcmp(argv[i], "-d") == 0)
-                       filter_parser_debug = 1;
-               else if (strcmp(argv[i], "-B") == 0)
-                       print_bytecode = 1;
-       }
-
-       /*
-        * Force generate the bytecode if the user asks to print the bytecode
-        * (can't print it without generating it first).
-        */
-       if (print_bytecode) {
-               generate_bytecode = 1;
-       }
-
-       /*
-        * Force generate the IR if the user asks to generate the bytecode
-        * (the bytecode is generated by visiting the IR).
-        */
-       if (generate_bytecode) {
-               generate_ir = 1;
-       }
-
-       ctx = filter_parser_ctx_alloc(stdin);
-       if (!ctx) {
-               fprintf(stderr, "Error allocating parser\n");
-               goto alloc_error;
-       }
-       ret = filter_parser_ctx_append_ast(ctx);
-       if (ret) {
-               fprintf(stderr, "Parse error\n");
-               goto parse_error;
-       }
-       if (print_xml) {
-               ret = filter_visitor_print_xml(ctx, stdout, 0);
-               if (ret) {
-                       fflush(stdout);
-                       fprintf(stderr, "XML print error\n");
-                       goto parse_error;
-               }
-       }
-       if (generate_ir) {
-               printf("Generating IR... ");
-               fflush(stdout);
-               ret = filter_visitor_ir_generate(ctx);
-               if (ret) {
-                       fprintf(stderr, "Generate IR error\n");
-                       goto parse_error;
-               }
-               printf("done\n");
-
-               printf("Validating IR... ");
-               fflush(stdout);
-               ret = filter_visitor_ir_check_binary_op_nesting(ctx);
-               if (ret) {
-                       goto parse_error;
-               }
-               printf("done\n");
-       }
-       if (generate_bytecode) {
-               printf("Generating bytecode... ");
-               fflush(stdout);
-               ret = filter_visitor_bytecode_generate(ctx);
-               if (ret) {
-                       fprintf(stderr, "Generate bytecode error\n");
-                       goto parse_error;
-               }
-               printf("done\n");
-               printf("Size of bytecode generated: %u bytes.\n",
-                       bytecode_get_len(&ctx->bytecode->b));
-       }
-
-       if (print_bytecode) {
-               unsigned int bytecode_len, len, i;
-
-               len = bytecode_get_len(&ctx->bytecode->b);
-               bytecode_len = ctx->bytecode->b.reloc_table_offset;
-               printf("Bytecode:\n");
-               for (i = 0; i < bytecode_len; i++) {
-                       printf("0x%X ",
-                               ((uint8_t *) ctx->bytecode->b.data)[i]);
-               }
-               printf("\n");
-               printf("Reloc table:\n");
-               for (i = bytecode_len; i < len;) {
-                       printf("{ 0x%X, ",
-                               *(uint16_t *) &ctx->bytecode->b.data[i]);
-                       i += sizeof(uint16_t);
-                       printf("%s } ", &((char *) ctx->bytecode->b.data)[i]);
-                       i += strlen(&((char *) ctx->bytecode->b.data)[i]) + 1;
-               }
-               printf("\n");
-       }
-
-       filter_bytecode_free(ctx);
-       filter_ir_free(ctx);
-       filter_parser_ctx_free(ctx);
-       return 0;
-
-parse_error:
-       filter_bytecode_free(ctx);
-       filter_ir_free(ctx);
-       filter_parser_ctx_free(ctx);
-alloc_error:
-       exit(EXIT_FAILURE);
-}
diff --git a/src/lib/lttng-ctl/filter/filter-ir.h b/src/lib/lttng-ctl/filter/filter-ir.h
deleted file mode 100644 (file)
index d62c0ee..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-#ifndef _FILTER_IR_H
-#define _FILTER_IR_H
-
-/*
- * filter-ir.h
- *
- * LTTng filter ir
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include "filter-ast.h"
-
-enum ir_op_signedness {
-       IR_SIGN_UNKNOWN = 0,
-       IR_SIGNED,
-       IR_UNSIGNED,
-       IR_SIGN_DYN,            /* signedness determined dynamically */
-};
-
-enum ir_data_type {
-       IR_DATA_UNKNOWN = 0,
-       IR_DATA_STRING,
-       IR_DATA_NUMERIC,        /* numeric and boolean */
-       IR_DATA_FLOAT,
-       IR_DATA_FIELD_REF,
-       IR_DATA_GET_CONTEXT_REF,
-       IR_DATA_EXPRESSION,
-};
-
-enum ir_op_type {
-       IR_OP_UNKNOWN = 0,
-       IR_OP_ROOT,
-       IR_OP_LOAD,
-       IR_OP_UNARY,
-       IR_OP_BINARY,
-       IR_OP_LOGICAL,
-};
-
-/* left or right child */
-enum ir_side {
-       IR_SIDE_UNKNOWN = 0,
-       IR_LEFT,
-       IR_RIGHT,
-};
-
-enum ir_load_string_type {
-       /* Plain, no globbing at all: `hello world`. */
-       IR_LOAD_STRING_TYPE_PLAIN = 0,
-
-       /* Star at the end only: `hello *`. */
-       IR_LOAD_STRING_TYPE_GLOB_STAR_END,
-
-       /* At least one star, anywhere, but not at the end only: `he*wor*`. */
-       IR_LOAD_STRING_TYPE_GLOB_STAR,
-};
-
-struct ir_op_root {
-       struct ir_op *child;
-};
-
-enum ir_load_expression_type {
-       IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT,
-       IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT,
-       IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT,
-       IR_LOAD_EXPRESSION_GET_SYMBOL,
-       IR_LOAD_EXPRESSION_GET_INDEX,
-       IR_LOAD_EXPRESSION_LOAD_FIELD,
-};
-
-struct ir_load_expression_op {
-       struct ir_load_expression_op *next;
-       enum ir_load_expression_type type;
-       union {
-               char *symbol;
-               uint64_t index;
-       } u;
-};
-
-struct ir_load_expression {
-       struct ir_load_expression_op *child;
-};
-
-struct ir_op_load {
-       union {
-               struct {
-                       enum ir_load_string_type type;
-                       char *value;
-               } string;
-               int64_t num;
-               double flt;
-               char *ref;
-               struct ir_load_expression *expression;
-       } u;
-};
-
-struct ir_op_unary {
-       enum unary_op_type type;
-       struct ir_op *child;
-};
-
-struct ir_op_binary {
-       enum op_type type;
-       struct ir_op *left;
-       struct ir_op *right;
-};
-
-struct ir_op_logical {
-       enum op_type type;
-       struct ir_op *left;
-       struct ir_op *right;
-};
-
-struct ir_op {
-       /* common to all ops */
-       enum ir_op_type op;
-       enum ir_data_type data_type;
-       enum ir_op_signedness signedness;
-       enum ir_side side;
-
-       union {
-               struct ir_op_root root;
-               struct ir_op_load load;
-               struct ir_op_unary unary;
-               struct ir_op_binary binary;
-               struct ir_op_logical logical;
-       } u;
-};
-
-#endif /* _FILTER_IR_H */
diff --git a/src/lib/lttng-ctl/filter/filter-lexer.l b/src/lib/lttng-ctl/filter/filter-lexer.l
deleted file mode 100644 (file)
index cdb099a..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-%{
-/*
- * filter-lexer.l
- *
- * LTTng filter lexer
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-
-static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
-       __attribute__((unused));
-static int input (yyscan_t yyscanner) __attribute__((unused));
-
-%}
-
-%x comment_ml comment_sl string_lit char_const
-%option reentrant yylineno noyywrap bison-bridge
-%option extra-type="struct filter_parser_ctx *"
-       /* bison-locations */
-
-D                              [0-9]
-L                              [a-zA-Z_]
-H                              [a-fA-F0-9]
-E                              ([Ee][+-]?{D}+)
-P                              ([Pp][+-]?{D}+)
-FS                             (f|F|l|L)
-IS                             ((u|U)|(u|U)?(l|L|ll|LL)|(l|L|ll|LL)(u|U))
-
-INTEGER_SUFFIX                 [ \n\t]*(U|UL|ULL|LU|LLU|Ul|Ull|lU|llU|u|uL|uLL|Lu|LLu|ul|ull|lu|llu)
-DIGIT                          [0-9]
-NONDIGIT                       [a-zA-Z_]
-HEXDIGIT                       [0-9A-Fa-f]
-OCTALDIGIT                     [0-7]
-UCHARLOWERCASE                 \\u{HEXDIGIT}{4}
-UCHARUPPERCASE                 \\U{HEXDIGIT}{8}
-ID_EXTRA_CHAR                  (":")
-ID_NONDIGIT                    {NONDIGIT}|{UCHARLOWERCASE}|{UCHARUPPERCASE}|{ID_EXTRA_CHAR}
-IDENTIFIER                     {ID_NONDIGIT}({ID_NONDIGIT}|{DIGIT})*
-ESCSEQ                         \\(\'|\"|\?|\\|a|b|f|n|r|t|v|{OCTALDIGIT}{1,3}|u{HEXDIGIT}{4}|U{HEXDIGIT}{8}|x{HEXDIGIT}+)
-%%
-
-                               /*
-                                * Using start conditions to deal with comments
-                                * and strings.
-                                */ 
-
-"/*"                           BEGIN(comment_ml);
-<comment_ml>[^*\n]*            /* eat anything that's not a '*' */
-<comment_ml>"*"+[^*/\n]*       /* eat up '*'s not followed by '/'s */
-<comment_ml>\n                 ++yylineno;
-<comment_ml>"*"+"/"            BEGIN(INITIAL);
-
-"//"                           BEGIN(comment_sl);
-<comment_sl>[^\n]*\n           ++yylineno; BEGIN(INITIAL);
-
-L\'                            BEGIN(char_const); return CHARACTER_CONSTANT_START;
-\'                             BEGIN(char_const); return CHARACTER_CONSTANT_START;
-<char_const>\'                 BEGIN(INITIAL); return SQUOTE;
-
-L\"                            BEGIN(string_lit); return STRING_LITERAL_START;
-\"                             BEGIN(string_lit); return STRING_LITERAL_START;
-<string_lit>\"                 BEGIN(INITIAL); return DQUOTE;
-
-<char_const,string_lit>ESCSEQ  return ESCSEQ;
-<char_const,string_lit>\n      ; /* ignore */
-<char_const,string_lit>.       setstring(yyextra, yylval, yytext); return CHAR_STRING_TOKEN;
-
-
-0[xX]{H}+{IS}?                 setstring(yyextra, yylval, yytext); return HEXADECIMAL_CONSTANT;
-0[0-7]*{IS}?                   setstring(yyextra, yylval, yytext); return OCTAL_CONSTANT;
-[1-9]{D}*{IS}?                 setstring(yyextra, yylval, yytext); return DECIMAL_CONSTANT;
-
-{D}+{E}{FS}?                   setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
-{D}*"."{D}+{E}?{FS}?           setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
-{D}+"."{D}*{E}?{FS}?           setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
-0[xX]{H}+{P}{FS}?              setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
-0[xX]{H}*"."{H}+{P}?{FS}?      setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
-0[xX]{H}+"."{H}*{P}?{FS}?      setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
-
-"["                            return LSBRAC;
-"]"                            return RSBRAC;
-"("                            return LPAREN;
-")"                            return RPAREN;
-"{"                            return LBRAC;
-"}"                            return RBRAC;
-"->"                           return RARROW;
-
-"*"                            return STAR;
-"+"                            return PLUS;
-"-"                            return MINUS;
-
-"%"                            return MOD_OP;
-"/"                            return DIV_OP;
-">>"                           return RIGHT_OP;
-"<<"                           return LEFT_OP;
-
-"=="                           return EQ_OP;
-"!="                           return NE_OP;
-"<="                           return LE_OP;
-">="                           return GE_OP;
-"<"                            return LT_OP;
-">"                            return GT_OP;
-"&&"                           return AND_OP;
-"||"                           return OR_OP;
-"!"                            return NOT_OP;
-
-":="                           return ASSIGN;
-":"                            return COLON;
-";"                            return SEMICOLON;
-"..."                          return DOTDOTDOT;
-"."                            return DOT;
-"="                            return EQUAL;
-","                            return COMMA;
-"^"                            return XOR_BIN;
-"&"                            return AND_BIN;
-"|"                            return OR_BIN;
-"~"                            return NOT_BIN;
-"$"{IDENTIFIER}                        printf_debug("<GLOBAL_IDENTIFIER %s>\n", yytext); setstring(yyextra, yylval, yytext); return GLOBAL_IDENTIFIER;
-{IDENTIFIER}                   printf_debug("<IDENTIFIER %s>\n", yytext); setstring(yyextra, yylval, yytext); return IDENTIFIER;
-[ \t\n]+                       ; /* ignore */
-.                              return ERROR;
-%%
diff --git a/src/lib/lttng-ctl/filter/filter-parser.y b/src/lib/lttng-ctl/filter/filter-parser.y
deleted file mode 100644 (file)
index ba2d300..0000000
+++ /dev/null
@@ -1,679 +0,0 @@
-%{
-/*
- * filter-parser.y
- *
- * LTTng filter expression parser
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- * Grammar inspired from http://www.quut.com/c/ANSI-C-grammar-y.html
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-
-#include <common/macros.h>
-
-#define WIDTH_u64_SCANF_IS_A_BROKEN_API        "20"
-#define WIDTH_o64_SCANF_IS_A_BROKEN_API        "22"
-#define WIDTH_x64_SCANF_IS_A_BROKEN_API        "17"
-#define WIDTH_lg_SCANF_IS_A_BROKEN_API "4096"  /* Hugely optimistic approximation */
-
-LTTNG_HIDDEN
-int yydebug;
-LTTNG_HIDDEN
-int filter_parser_debug = 0;
-
-LTTNG_HIDDEN
-int yyparse(struct filter_parser_ctx *parser_ctx, yyscan_t scanner);
-LTTNG_HIDDEN
-int yylex(union YYSTYPE *yyval, yyscan_t scanner);
-LTTNG_HIDDEN
-int yylex_init_extra(struct filter_parser_ctx *parser_ctx, yyscan_t * ptr_yy_globals);
-LTTNG_HIDDEN
-int yylex_destroy(yyscan_t yyparser_ctx);
-LTTNG_HIDDEN
-void yyrestart(FILE * in_str, yyscan_t parser_ctx);
-
-struct gc_string {
-       struct cds_list_head gc;
-       size_t alloclen;
-       char s[];
-};
-
-static const char *node_type_to_str[] = {
-       [ NODE_UNKNOWN ] = "NODE_UNKNOWN",
-       [ NODE_ROOT ] = "NODE_ROOT",
-       [ NODE_EXPRESSION ] = "NODE_EXPRESSION",
-       [ NODE_OP ] = "NODE_OP",
-       [ NODE_UNARY_OP ] = "NODE_UNARY_OP",
-};
-
-LTTNG_HIDDEN
-const char *node_type(struct filter_node *node)
-{
-       if (node->type < NR_NODE_TYPES)
-               return node_type_to_str[node->type];
-       else
-               return NULL;
-}
-
-static struct gc_string *gc_string_alloc(struct filter_parser_ctx *parser_ctx,
-                                        size_t len)
-{
-       struct gc_string *gstr;
-       size_t alloclen;
-
-       /* TODO: could be faster with find first bit or glib Gstring */
-       /* sizeof long to account for malloc header (int or long ?) */
-       for (alloclen = 8; alloclen < sizeof(long) + sizeof(*gstr) + len;
-            alloclen *= 2);
-
-       gstr = zmalloc(alloclen);
-       if (!gstr) {
-               goto end;
-       }
-       cds_list_add(&gstr->gc, &parser_ctx->allocated_strings);
-       gstr->alloclen = alloclen;
-end:
-       return gstr;
-}
-
-/*
- * note: never use gc_string_append on a string that has external references.
- * gsrc will be garbage collected immediately, and gstr might be.
- * Should only be used to append characters to a string literal or constant.
- */
-static
-struct gc_string *gc_string_append(struct filter_parser_ctx *parser_ctx,
-                                  struct gc_string *gstr,
-                                  struct gc_string *gsrc)
-{
-       size_t newlen = strlen(gsrc->s) + strlen(gstr->s) + 1;
-       size_t alloclen;
-
-       /* TODO: could be faster with find first bit or glib Gstring */
-       /* sizeof long to account for malloc header (int or long ?) */
-       for (alloclen = 8; alloclen < sizeof(long) + sizeof(*gstr) + newlen;
-            alloclen *= 2);
-
-       if (alloclen > gstr->alloclen) {
-               struct gc_string *newgstr;
-
-               newgstr = gc_string_alloc(parser_ctx, newlen);
-               strcpy(newgstr->s, gstr->s);
-               strcat(newgstr->s, gsrc->s);
-               cds_list_del(&gstr->gc);
-               free(gstr);
-               gstr = newgstr;
-       } else {
-               strcat(gstr->s, gsrc->s);
-       }
-       cds_list_del(&gsrc->gc);
-       free(gsrc);
-       return gstr;
-}
-
-LTTNG_HIDDEN
-void setstring(struct filter_parser_ctx *parser_ctx, YYSTYPE *lvalp, const char *src)
-{
-       lvalp->gs = gc_string_alloc(parser_ctx, strlen(src) + 1);
-       strcpy(lvalp->gs->s, src);
-}
-
-static struct filter_node *make_node(struct filter_parser_ctx *scanner,
-                                 enum node_type type)
-{
-       struct filter_ast *ast = filter_parser_get_ast(scanner);
-       struct filter_node *node;
-
-       node = zmalloc(sizeof(*node));
-       if (!node)
-               return NULL;
-       memset(node, 0, sizeof(*node));
-       node->type = type;
-       cds_list_add(&node->gc, &ast->allocated_nodes);
-
-       switch (type) {
-       case NODE_ROOT:
-               fprintf(stderr, "[error] %s: trying to create root node\n", __func__);
-               break;
-
-       case NODE_EXPRESSION:
-               break;
-       case NODE_OP:
-               break;
-       case NODE_UNARY_OP:
-               break;
-
-       case NODE_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown node type %d\n", __func__,
-                       (int) type);
-               break;
-       }
-
-       return node;
-}
-
-static struct filter_node *make_op_node(struct filter_parser_ctx *scanner,
-                       enum op_type type,
-                       struct filter_node *lchild,
-                       struct filter_node *rchild)
-{
-       struct filter_ast *ast = filter_parser_get_ast(scanner);
-       struct filter_node *node;
-
-       node = zmalloc(sizeof(*node));
-       if (!node)
-               return NULL;
-       memset(node, 0, sizeof(*node));
-       node->type = NODE_OP;
-       cds_list_add(&node->gc, &ast->allocated_nodes);
-       node->u.op.type = type;
-       node->u.op.lchild = lchild;
-       node->u.op.rchild = rchild;
-       return node;
-}
-
-static
-void yyerror(struct filter_parser_ctx *parser_ctx, yyscan_t scanner, const char *str)
-{
-       fprintf(stderr, "error %s\n", str);
-}
-
-#define parse_error(parser_ctx, str)                           \
-do {                                                           \
-       yyerror(parser_ctx, parser_ctx->scanner, YY_("parse error: " str "\n"));        \
-       YYERROR;                                                \
-} while (0)
-
-static void free_strings(struct cds_list_head *list)
-{
-       struct gc_string *gstr, *tmp;
-
-       cds_list_for_each_entry_safe(gstr, tmp, list, gc)
-               free(gstr);
-}
-
-static struct filter_ast *filter_ast_alloc(void)
-{
-       struct filter_ast *ast;
-
-       ast = zmalloc(sizeof(*ast));
-       if (!ast)
-               return NULL;
-       memset(ast, 0, sizeof(*ast));
-       CDS_INIT_LIST_HEAD(&ast->allocated_nodes);
-       ast->root.type = NODE_ROOT;
-       return ast;
-}
-
-static void filter_ast_free(struct filter_ast *ast)
-{
-       struct filter_node *node, *tmp;
-
-       cds_list_for_each_entry_safe(node, tmp, &ast->allocated_nodes, gc)
-               free(node);
-       free(ast);
-}
-
-LTTNG_HIDDEN
-int filter_parser_ctx_append_ast(struct filter_parser_ctx *parser_ctx)
-{
-       return yyparse(parser_ctx, parser_ctx->scanner);
-}
-
-LTTNG_HIDDEN
-struct filter_parser_ctx *filter_parser_ctx_alloc(FILE *input)
-{
-       struct filter_parser_ctx *parser_ctx;
-       int ret;
-
-       yydebug = filter_parser_debug;
-
-       parser_ctx = zmalloc(sizeof(*parser_ctx));
-       if (!parser_ctx)
-               return NULL;
-       memset(parser_ctx, 0, sizeof(*parser_ctx));
-
-       ret = yylex_init_extra(parser_ctx, &parser_ctx->scanner);
-       if (ret) {
-               fprintf(stderr, "yylex_init error\n");
-               goto cleanup_parser_ctx;
-       }
-       /* Start processing new stream */
-       yyrestart(input, parser_ctx->scanner);
-
-       parser_ctx->ast = filter_ast_alloc();
-       if (!parser_ctx->ast)
-               goto cleanup_lexer;
-       CDS_INIT_LIST_HEAD(&parser_ctx->allocated_strings);
-
-       if (yydebug)
-               fprintf(stdout, "parser_ctx input is a%s.\n",
-                       isatty(fileno(input)) ? "n interactive tty" :
-                                               " noninteractive file");
-
-       return parser_ctx;
-
-cleanup_lexer:
-       ret = yylex_destroy(parser_ctx->scanner);
-       if (!ret)
-               fprintf(stderr, "yylex_destroy error\n");
-cleanup_parser_ctx:
-       free(parser_ctx);
-       return NULL;
-}
-
-LTTNG_HIDDEN
-void filter_parser_ctx_free(struct filter_parser_ctx *parser_ctx)
-{
-       int ret;
-
-       free_strings(&parser_ctx->allocated_strings);
-       filter_ast_free(parser_ctx->ast);
-       ret = yylex_destroy(parser_ctx->scanner);
-       if (ret)
-               fprintf(stderr, "yylex_destroy error\n");
-       free(parser_ctx);
-}
-
-%}
-
-%code provides
-{
-#include "common/macros.h"
-
-LTTNG_HIDDEN
-void setstring(struct filter_parser_ctx *parser_ctx, YYSTYPE *lvalp, const char *src);
-}
-
-%define api.pure
-       /* %locations */
-%parse-param {struct filter_parser_ctx *parser_ctx}
-%parse-param {yyscan_t scanner}
-%lex-param {yyscan_t scanner}
-%start translation_unit
-%token CHARACTER_CONSTANT_START SQUOTE STRING_LITERAL_START DQUOTE
-%token ESCSEQ CHAR_STRING_TOKEN
-%token DECIMAL_CONSTANT OCTAL_CONSTANT HEXADECIMAL_CONSTANT FLOAT_CONSTANT
-%token LSBRAC RSBRAC LPAREN RPAREN LBRAC RBRAC RARROW
-%token STAR PLUS MINUS
-%token MOD_OP DIV_OP RIGHT_OP LEFT_OP
-%token EQ_OP NE_OP LE_OP GE_OP LT_OP GT_OP AND_OP OR_OP NOT_OP
-%token ASSIGN COLON SEMICOLON DOTDOTDOT DOT EQUAL COMMA
-%token XOR_BIN AND_BIN OR_BIN NOT_BIN
-
-%token <gs> IDENTIFIER GLOBAL_IDENTIFIER
-%token ERROR
-%union
-{
-       long long ll;
-       char c;
-       struct gc_string *gs;
-       struct filter_node *n;
-}
-
-%type <gs> s_char s_char_sequence c_char c_char_sequence
-
-%type <n> primary_expression
-%type <n> prefix_expression
-%type <n> prefix_expression_rec
-%type <n> postfix_expression
-%type <n> unary_expression
-%type <n> unary_operator
-%type <n> multiplicative_expression
-%type <n> additive_expression
-%type <n> shift_expression
-%type <n> relational_expression
-%type <n> equality_expression
-%type <n> and_expression
-%type <n> exclusive_or_expression
-%type <n> inclusive_or_expression
-%type <n> logical_and_expression
-%type <n> logical_or_expression
-%type <n> expression
-%type <n> identifiers
-
-%%
-
-
-/* 1.5 Constants */
-
-c_char_sequence:
-               c_char
-               {       $$ = $1;                                        }
-       |       c_char_sequence c_char
-               {       $$ = gc_string_append(parser_ctx, $1, $2);              }
-       ;
-
-c_char:
-               CHAR_STRING_TOKEN
-               {       $$ = yylval.gs;                                 }
-       |       ESCSEQ
-               {
-                       parse_error(parser_ctx, "escape sequences not supported yet");
-               }
-       ;
-
-/* 1.6 String literals */
-
-s_char_sequence:
-               s_char
-               {       $$ = $1;                                        }
-       |       s_char_sequence s_char
-               {       $$ = gc_string_append(parser_ctx, $1, $2);              }
-       ;
-
-s_char:
-               CHAR_STRING_TOKEN
-               {       $$ = yylval.gs;                                 }
-       |       ESCSEQ
-               {
-                       parse_error(parser_ctx, "escape sequences not supported yet");
-               }
-       ;
-
-primary_expression:
-               DECIMAL_CONSTANT
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_CONSTANT;
-                       if (sscanf(yylval.gs->s, "%" WIDTH_u64_SCANF_IS_A_BROKEN_API SCNu64,
-                                       &$$->u.expression.u.constant) != 1) {
-                               parse_error(parser_ctx, "cannot scanf decimal constant");
-                       }
-               }
-       |       OCTAL_CONSTANT
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_CONSTANT;
-                       if (!strcmp(yylval.gs->s, "0")) {
-                               $$->u.expression.u.constant = 0;
-                       } else if (sscanf(yylval.gs->s, "0%" WIDTH_o64_SCANF_IS_A_BROKEN_API SCNo64,
-                                       &$$->u.expression.u.constant) != 1) {
-                               parse_error(parser_ctx, "cannot scanf octal constant");
-                       }
-               }
-       |       HEXADECIMAL_CONSTANT
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_CONSTANT;
-                       if (sscanf(yylval.gs->s, "0x%" WIDTH_x64_SCANF_IS_A_BROKEN_API SCNx64,
-                                       &$$->u.expression.u.constant) != 1) {
-                               parse_error(parser_ctx, "cannot scanf hexadecimal constant");
-                       }
-               }
-       |       FLOAT_CONSTANT
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_FLOAT_CONSTANT;
-                       if (sscanf(yylval.gs->s, "%" WIDTH_lg_SCANF_IS_A_BROKEN_API "lg",
-                                       &$$->u.expression.u.float_constant) != 1) {
-                               parse_error(parser_ctx, "cannot scanf float constant");
-                       }
-               }
-       |       STRING_LITERAL_START DQUOTE
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_STRING;
-                       $$->u.expression.u.string = "";
-               }
-       |       STRING_LITERAL_START s_char_sequence DQUOTE
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_STRING;
-                       $$->u.expression.u.string = $2->s;
-               }
-       |       CHARACTER_CONSTANT_START c_char_sequence SQUOTE
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_STRING;
-                       $$->u.expression.u.string = $2->s;
-               }
-       |       LPAREN expression RPAREN
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_NESTED;
-                       $$->u.expression.u.child = $2;
-               }
-       ;
-
-identifiers
-       :       IDENTIFIER
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_IDENTIFIER;
-                       $$->u.expression.u.identifier = yylval.gs->s;
-               }
-       |       GLOBAL_IDENTIFIER
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_GLOBAL_IDENTIFIER;
-                       $$->u.expression.u.identifier = yylval.gs->s;
-               }
-       ;
-
-prefix_expression_rec
-       : LSBRAC unary_expression RSBRAC
-               {
-                       $$ = $2;
-               }
-       | LSBRAC unary_expression RSBRAC prefix_expression_rec
-               {
-                       $$ = $2;
-                       $$->u.expression.pre_op = AST_LINK_BRACKET;
-                       $$->u.expression.prev = $4;
-               }
-       ;
-
-prefix_expression
-       : identifiers
-               {
-                       $$ = $1;
-               }
-       | identifiers prefix_expression_rec
-               {
-                       $$ = $1;
-                       $$->u.expression.pre_op = AST_LINK_BRACKET;
-                       $$->u.expression.next_bracket = $2;
-               }
-       ;
-
-postfix_expression
-       : prefix_expression
-               {
-                       $$ = $1;
-               }
-       | postfix_expression DOT prefix_expression
-               {
-                       $$ = $3;
-                       $$->u.expression.post_op = AST_LINK_DOT;
-                       $$->u.expression.prev = $1;
-               }
-       | postfix_expression RARROW prefix_expression
-               {
-                       $$ = $3;
-                       $$->u.expression.post_op = AST_LINK_RARROW;
-                       $$->u.expression.prev = $1;
-               }
-       ;
-
-unary_expression
-       : postfix_expression
-               {       $$ = $1;                                        }
-       | primary_expression
-               {       $$ = $1;                                        }
-       | unary_operator unary_expression
-               {
-                       $$ = $1;
-                       $$->u.unary_op.child = $2;
-               }
-       ;
-
-unary_operator
-       : PLUS
-               {
-                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
-                       $$->u.unary_op.type = AST_UNARY_PLUS;
-               }
-       | MINUS
-               {
-                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
-                       $$->u.unary_op.type = AST_UNARY_MINUS;
-               }
-       | NOT_OP
-               {
-                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
-                       $$->u.unary_op.type = AST_UNARY_NOT;
-               }
-       | NOT_BIN
-               {
-                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
-                       $$->u.unary_op.type = AST_UNARY_BIT_NOT;
-               }
-       ;
-
-multiplicative_expression
-       : unary_expression
-               {       $$ = $1;                                        }
-       | multiplicative_expression STAR unary_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_MUL, $1, $3);
-               }
-       | multiplicative_expression DIV_OP unary_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_DIV, $1, $3);
-               }
-       | multiplicative_expression MOD_OP unary_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_MOD, $1, $3);
-               }
-       ;
-
-additive_expression
-       : multiplicative_expression
-               {       $$ = $1;                                        }
-       | additive_expression PLUS multiplicative_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_PLUS, $1, $3);
-               }
-       | additive_expression MINUS multiplicative_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_MINUS, $1, $3);
-               }
-       ;
-
-shift_expression
-       : additive_expression
-               {       $$ = $1;                                        }
-       | shift_expression LEFT_OP additive_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_BIT_LSHIFT, $1, $3);
-               }
-       | shift_expression RIGHT_OP additive_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_BIT_RSHIFT, $1, $3);
-               }
-       ;
-
-and_expression
-       : shift_expression
-               {       $$ = $1;                                        }
-       | and_expression AND_BIN shift_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_BIT_AND, $1, $3);
-               }
-       ;
-
-exclusive_or_expression
-       : and_expression
-               {       $$ = $1;                                        }
-       | exclusive_or_expression XOR_BIN and_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_BIT_XOR, $1, $3);
-               }
-       ;
-
-inclusive_or_expression
-       : exclusive_or_expression
-               {       $$ = $1;                                        }
-       | inclusive_or_expression OR_BIN exclusive_or_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_BIT_OR, $1, $3);
-               }
-       ;
-
-relational_expression
-       : inclusive_or_expression
-               {       $$ = $1;                                        }
-       | relational_expression LT_OP inclusive_or_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_LT, $1, $3);
-               }
-       | relational_expression GT_OP inclusive_or_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_GT, $1, $3);
-               }
-       | relational_expression LE_OP inclusive_or_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_LE, $1, $3);
-               }
-       | relational_expression GE_OP inclusive_or_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_GE, $1, $3);
-               }
-       ;
-
-equality_expression
-       : relational_expression
-               {       $$ = $1;                                        }
-       | equality_expression EQ_OP relational_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_EQ, $1, $3);
-               }
-       | equality_expression NE_OP relational_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_NE, $1, $3);
-               }
-       ;
-
-logical_and_expression
-       : equality_expression
-               {       $$ = $1;                                        }
-       | logical_and_expression AND_OP equality_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_AND, $1, $3);
-               }
-       ;
-
-logical_or_expression
-       : logical_and_expression
-               {       $$ = $1;                                        }
-       | logical_or_expression OR_OP logical_and_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_OR, $1, $3);
-               }
-       ;
-
-expression
-       : logical_or_expression
-               {       $$ = $1;                                        }
-       ;
-
-translation_unit
-       : expression
-               {
-                       parser_ctx->ast->root.u.root.child = $1;
-               }
-       ;
diff --git a/src/lib/lttng-ctl/filter/filter-symbols.h b/src/lib/lttng-ctl/filter/filter-symbols.h
deleted file mode 100644 (file)
index 031776d..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef _FILTER_SYMBOLS_H
-#define _FILTER_SYMBOLS_H
-
-/*
- * filter-symbols.h
- *
- * LTTng filter flex/bison symbol prefixes
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#define yy_create_buffer lttng_yy_create_buffer
-#define yy_delete_buffer lttng_yy_delete_buffer
-#define yy_flush_buffer lttng_yy_flush_buffer
-#define yy_scan_buffer lttng_yy_scan_buffer
-#define yy_scan_bytes lttng_yy_scan_bytes
-#define yy_scan_string lttng_yy_scan_string
-#define yy_switch_to_buffer lttng_yy_switch_to_buffer
-#define yyalloc lttng_yyalloc
-#define yyfree lttng_yyfree
-#define yyget_column lttng_yyget_column
-#define yyget_debug lttng_yyget_debug
-#define yyget_extra lttng_yyget_extra
-#define yyget_in lttng_yyget_in
-#define yyget_leng lttng_yyget_leng
-#define yyget_lineno lttng_yyget_lineno
-#define yyget_lval lttng_yyget_lval
-#define yyget_out lttng_yyget_out
-#define yyget_text lttng_yyget_text
-#define yylex_init lttng_yylex_init
-#define yypop_buffer_state lttng_yypop_buffer_state
-#define yypush_buffer_state lttng_yypush_buffer_state
-#define yyrealloc lttng_yyrealloc
-#define yyset_column lttng_yyset_column
-#define yyset_debug lttng_yyset_debug
-#define yyset_extra lttng_yyset_extra
-#define yyset_in lttng_yyset_in
-#define yyset_lineno lttng_yyset_lineno
-#define yyset_lval lttng_yyset_lval
-#define yyset_out lttng_yyset_out
-
-#endif /* _FILTER_SYMBOLS_H */
diff --git a/src/lib/lttng-ctl/filter/filter-visitor-generate-bytecode.c b/src/lib/lttng-ctl/filter/filter-visitor-generate-bytecode.c
deleted file mode 100644 (file)
index 699273c..0000000
+++ /dev/null
@@ -1,830 +0,0 @@
-/*
- * filter-visitor-generate-bytecode.c
- *
- * LTTng filter bytecode generation
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <common/align.h>
-#include <common/compat/string.h>
-
-#include "filter-bytecode.h"
-#include "filter-ir.h"
-#include "filter-ast.h"
-
-#include <common/macros.h>
-
-#ifndef max_t
-#define max_t(type, a, b)      ((type) ((a) > (b) ? (a) : (b)))
-#endif
-
-#define INIT_ALLOC_SIZE                4
-
-static
-int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
-               struct ir_op *node);
-
-static inline int get_count_order(unsigned int count)
-{
-       int order;
-
-       order = lttng_fls(count) - 1;
-       if (count & (count - 1))
-               order++;
-       return order;
-}
-
-static
-int bytecode_init(struct lttng_filter_bytecode_alloc **fb)
-{
-       uint32_t alloc_len;
-
-       alloc_len = sizeof(struct lttng_filter_bytecode_alloc) + INIT_ALLOC_SIZE;
-       *fb = calloc(alloc_len, 1);
-       if (!*fb) {
-               return -ENOMEM;
-       } else {
-               (*fb)->alloc_len = alloc_len;
-               return 0;
-       }
-}
-
-static
-int32_t bytecode_reserve(struct lttng_filter_bytecode_alloc **fb, uint32_t align, uint32_t len)
-{
-       int32_t ret;
-       uint32_t padding = offset_align((*fb)->b.len, align);
-       uint32_t new_len = (*fb)->b.len + padding + len;
-       uint32_t new_alloc_len = sizeof(struct lttng_filter_bytecode_alloc) + new_len;
-       uint32_t old_alloc_len = (*fb)->alloc_len;
-
-       if (new_len > LTTNG_FILTER_MAX_LEN)
-               return -EINVAL;
-
-       if (new_alloc_len > old_alloc_len) {
-               struct lttng_filter_bytecode_alloc *newptr;
-
-               new_alloc_len =
-                       max_t(uint32_t, 1U << get_count_order(new_alloc_len), old_alloc_len << 1);
-               newptr = realloc(*fb, new_alloc_len);
-               if (!newptr)
-                       return -ENOMEM;
-               *fb = newptr;
-               /* We zero directly the memory from start of allocation. */
-               memset(&((char *) *fb)[old_alloc_len], 0, new_alloc_len - old_alloc_len);
-               (*fb)->alloc_len = new_alloc_len;
-       }
-       (*fb)->b.len += padding;
-       ret = (*fb)->b.len;
-       (*fb)->b.len += len;
-       return ret;
-}
-
-static
-int bytecode_push(struct lttng_filter_bytecode_alloc **fb, const void *data,
-               uint32_t align, uint32_t len)
-{
-       int32_t offset;
-
-       offset = bytecode_reserve(fb, align, len);
-       if (offset < 0)
-               return offset;
-       memcpy(&(*fb)->b.data[offset], data, len);
-       return 0;
-}
-
-static
-int bytecode_push_logical(struct lttng_filter_bytecode_alloc **fb,
-               struct logical_op *data,
-               uint32_t align, uint32_t len,
-               uint16_t *skip_offset)
-{
-       int32_t offset;
-
-       offset = bytecode_reserve(fb, align, len);
-       if (offset < 0)
-               return offset;
-       memcpy(&(*fb)->b.data[offset], data, len);
-       *skip_offset =
-               (void *) &((struct logical_op *) &(*fb)->b.data[offset])->skip_offset
-                       - (void *) &(*fb)->b.data[0];
-       return 0;
-}
-
-static
-int bytecode_patch(struct lttng_filter_bytecode_alloc **fb,
-               const void *data,
-               uint16_t offset,
-               uint32_t len)
-{
-       if (offset >= (*fb)->b.len) {
-               return -EINVAL;
-       }
-       memcpy(&(*fb)->b.data[offset], data, len);
-       return 0;
-}
-
-static
-int visit_node_root(struct filter_parser_ctx *ctx, struct ir_op *node)
-{
-       int ret;
-       struct return_op insn;
-
-       /* Visit child */
-       ret = recursive_visit_gen_bytecode(ctx, node->u.root.child);
-       if (ret)
-               return ret;
-
-       /* Generate end of bytecode instruction */
-       insn.op = FILTER_OP_RETURN;
-       return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
-}
-
-static
-int append_str(char **s, const char *append)
-{
-       char *old = *s;
-       char *new;
-       size_t oldlen = (old == NULL) ? 0 : strlen(old);
-       size_t appendlen = strlen(append);
-
-       new = calloc(oldlen + appendlen + 1, 1);
-       if (!new) {
-               return -ENOMEM;
-       }
-       if (oldlen) {
-               strcpy(new, old);
-       }
-       strcat(new, append);
-       *s = new;
-       free(old);
-       return 0;
-}
-
-/*
- * 1: match
- * 0: no match
- * < 0: error
- */
-static
-int load_expression_legacy_match(const struct ir_load_expression *exp,
-               enum filter_op *op_type,
-               char **symbol)
-{
-       const struct ir_load_expression_op *op;
-       bool need_dot = false;
-
-       op = exp->child;
-       switch (op->type) {
-       case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
-               *op_type = FILTER_OP_GET_CONTEXT_REF;
-               if (append_str(symbol, "$ctx.")) {
-                       return -ENOMEM;
-               }
-               need_dot = false;
-               break;
-       case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
-               *op_type = FILTER_OP_GET_CONTEXT_REF;
-               if (append_str(symbol, "$app.")) {
-                       return -ENOMEM;
-               }
-               need_dot = false;
-               break;
-       case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
-               *op_type = FILTER_OP_LOAD_FIELD_REF;
-               need_dot = false;
-               break;
-
-       case IR_LOAD_EXPRESSION_GET_SYMBOL:
-       case IR_LOAD_EXPRESSION_GET_INDEX:
-       case IR_LOAD_EXPRESSION_LOAD_FIELD:
-       default:
-               return 0;       /* no match */
-       }
-
-       for (;;) {
-               op = op->next;
-               if (!op) {
-                       return 0;       /* no match */
-               }
-               switch (op->type) {
-               case IR_LOAD_EXPRESSION_LOAD_FIELD:
-                       goto end;
-               case IR_LOAD_EXPRESSION_GET_SYMBOL:
-                       if (need_dot && append_str(symbol, ".")) {
-                               return -ENOMEM;
-                       }
-                       if (append_str(symbol, op->u.symbol)) {
-                               return -ENOMEM;
-                       }
-                       break;
-               default:
-                       return 0;        /* no match */
-               }
-               need_dot = true;
-       }
-end:
-       return 1;       /* Legacy match */
-}
-
-/*
- * 1: legacy match
- * 0: no legacy match
- * < 0: error
- */
-static
-int visit_node_load_expression_legacy(struct filter_parser_ctx *ctx,
-               const struct ir_load_expression *exp,
-               const struct ir_load_expression_op *op)
-{
-       struct load_op *insn = NULL;
-       uint32_t insn_len = sizeof(struct load_op)
-               + sizeof(struct field_ref);
-       struct field_ref ref_offset;
-       uint32_t reloc_offset_u32;
-       uint16_t reloc_offset;
-       enum filter_op op_type;
-       char *symbol = NULL;
-       int ret;
-
-       ret = load_expression_legacy_match(exp, &op_type, &symbol);
-       if (ret <= 0) {
-               goto end;
-       }
-       insn = calloc(insn_len, 1);
-       if (!insn) {
-               ret = -ENOMEM;
-               goto end;
-       }
-       insn->op = op_type;
-       ref_offset.offset = (uint16_t) -1U;
-       memcpy(insn->data, &ref_offset, sizeof(ref_offset));
-       /* reloc_offset points to struct load_op */
-       reloc_offset_u32 = bytecode_get_len(&ctx->bytecode->b);
-       if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) {
-               ret = -EINVAL;
-               goto end;
-       }
-       reloc_offset = (uint16_t) reloc_offset_u32;
-       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-       if (ret) {
-               goto end;
-       }
-       /* append reloc */
-       ret = bytecode_push(&ctx->bytecode_reloc, &reloc_offset,
-                               1, sizeof(reloc_offset));
-       if (ret) {
-               goto end;
-       }
-       ret = bytecode_push(&ctx->bytecode_reloc, symbol,
-                               1, strlen(symbol) + 1);
-       if (ret) {
-               goto end;
-       }
-       ret = 1;        /* legacy */
-end:
-       free(insn);
-       free(symbol);
-       return ret;
-}
-
-static
-int visit_node_load_expression(struct filter_parser_ctx *ctx,
-               const struct ir_op *node)
-{
-       struct ir_load_expression *exp;
-       struct ir_load_expression_op *op;
-       int ret;
-
-       exp = node->u.load.u.expression;
-       if (!exp) {
-               return -EINVAL;
-       }
-       op = exp->child;
-       if (!op) {
-               return -EINVAL;
-       }
-
-       /*
-        * TODO: if we remove legacy load for application contexts, we
-        * need to update session bytecode parser as well.
-        */
-       ret = visit_node_load_expression_legacy(ctx, exp, op);
-       if (ret < 0) {
-               return ret;
-       }
-       if (ret > 0) {
-               return 0;       /* legacy */
-       }
-
-       for (; op != NULL; op = op->next) {
-               switch (op->type) {
-               case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
-               {
-                       struct load_op *insn;
-                       uint32_t insn_len = sizeof(struct load_op);
-                       int ret;
-
-                       insn = calloc(insn_len, 1);
-                       if (!insn)
-                               return -ENOMEM;
-                       insn->op = FILTER_OP_GET_CONTEXT_ROOT;
-                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-                       free(insn);
-                       if (ret) {
-                               return ret;
-                       }
-                       break;
-               }
-               case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
-               {
-                       struct load_op *insn;
-                       uint32_t insn_len = sizeof(struct load_op);
-                       int ret;
-
-                       insn = calloc(insn_len, 1);
-                       if (!insn)
-                               return -ENOMEM;
-                       insn->op = FILTER_OP_GET_APP_CONTEXT_ROOT;
-                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-                       free(insn);
-                       if (ret) {
-                               return ret;
-                       }
-                       break;
-               }
-               case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
-               {
-                       struct load_op *insn;
-                       uint32_t insn_len = sizeof(struct load_op);
-                       int ret;
-
-                       insn = calloc(insn_len, 1);
-                       if (!insn)
-                               return -ENOMEM;
-                       insn->op = FILTER_OP_GET_PAYLOAD_ROOT;
-                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-                       free(insn);
-                       if (ret) {
-                               return ret;
-                       }
-                       break;
-               }
-               case IR_LOAD_EXPRESSION_GET_SYMBOL:
-               {
-                       struct load_op *insn;
-                       uint32_t insn_len = sizeof(struct load_op)
-                               + sizeof(struct get_symbol);
-                       struct get_symbol symbol_offset;
-                       uint32_t reloc_offset_u32;
-                       uint16_t reloc_offset;
-                       uint32_t bytecode_reloc_offset_u32;
-                       int ret;
-
-                       insn = calloc(insn_len, 1);
-                       if (!insn)
-                               return -ENOMEM;
-                       insn->op = FILTER_OP_GET_SYMBOL;
-                       bytecode_reloc_offset_u32 =
-                                       bytecode_get_len(&ctx->bytecode_reloc->b)
-                                       + sizeof(reloc_offset);
-                       symbol_offset.offset =
-                                       (uint16_t) bytecode_reloc_offset_u32;
-                       memcpy(insn->data, &symbol_offset,
-                                       sizeof(symbol_offset));
-                       /* reloc_offset points to struct load_op */
-                       reloc_offset_u32 = bytecode_get_len(&ctx->bytecode->b);
-                       if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) {
-                               free(insn);
-                               return -EINVAL;
-                       }
-                       reloc_offset = (uint16_t) reloc_offset_u32;
-                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-                       if (ret) {
-                               free(insn);
-                               return ret;
-                       }
-                       /* append reloc */
-                       ret = bytecode_push(&ctx->bytecode_reloc, &reloc_offset,
-                                       1, sizeof(reloc_offset));
-                       if (ret) {
-                               free(insn);
-                               return ret;
-                       }
-                       ret = bytecode_push(&ctx->bytecode_reloc,
-                                       op->u.symbol,
-                                       1, strlen(op->u.symbol) + 1);
-                       free(insn);
-                       if (ret) {
-                               return ret;
-                       }
-                       break;
-               }
-               case IR_LOAD_EXPRESSION_GET_INDEX:
-               {
-                       struct load_op *insn;
-                       uint32_t insn_len = sizeof(struct load_op)
-                               + sizeof(struct get_index_u64);
-                       struct get_index_u64 index;
-                       int ret;
-
-                       insn = calloc(insn_len, 1);
-                       if (!insn)
-                               return -ENOMEM;
-                       insn->op = FILTER_OP_GET_INDEX_U64;
-                       index.index = op->u.index;
-                       memcpy(insn->data, &index, sizeof(index));
-                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-                       free(insn);
-                       if (ret) {
-                               return ret;
-                       }
-                       break;
-               }
-               case IR_LOAD_EXPRESSION_LOAD_FIELD:
-               {
-                       struct load_op *insn;
-                       uint32_t insn_len = sizeof(struct load_op);
-                       int ret;
-
-                       insn = calloc(insn_len, 1);
-                       if (!insn)
-                               return -ENOMEM;
-                       insn->op = FILTER_OP_LOAD_FIELD;
-                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-                       free(insn);
-                       if (ret) {
-                               return ret;
-                       }
-                       break;
-               }
-               }
-       }
-       return 0;
-}
-
-static
-int visit_node_load(struct filter_parser_ctx *ctx, struct ir_op *node)
-{
-       int ret;
-
-       switch (node->data_type) {
-       case IR_DATA_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] Unknown data type in %s\n",
-                       __func__);
-               return -EINVAL;
-
-       case IR_DATA_STRING:
-       {
-               struct load_op *insn;
-               uint32_t insn_len = sizeof(struct load_op)
-                       + strlen(node->u.load.u.string.value) + 1;
-
-               insn = calloc(insn_len, 1);
-               if (!insn)
-                       return -ENOMEM;
-
-               switch (node->u.load.u.string.type) {
-               case IR_LOAD_STRING_TYPE_GLOB_STAR:
-                       /*
-                        * We explicitly tell the interpreter here that
-                        * this load is a full star globbing pattern so
-                        * that the appropriate matching function can be
-                        * called. Also, see comment below.
-                        */
-                       insn->op = FILTER_OP_LOAD_STAR_GLOB_STRING;
-                       break;
-               default:
-                       /*
-                        * This is the "legacy" string, which includes
-                        * star globbing patterns with a star only at
-                        * the end. Both "plain" and "star at the end"
-                        * literal strings are handled at the same place
-                        * by the tracer's filter bytecode interpreter,
-                        * whereas full star globbing patterns (stars
-                        * can be anywhere in the string) is a special
-                        * case.
-                        */
-                       insn->op = FILTER_OP_LOAD_STRING;
-                       break;
-               }
-
-               strcpy(insn->data, node->u.load.u.string.value);
-               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-               free(insn);
-               return ret;
-       }
-       case IR_DATA_NUMERIC:
-       {
-               struct load_op *insn;
-               uint32_t insn_len = sizeof(struct load_op)
-                       + sizeof(struct literal_numeric);
-
-               insn = calloc(insn_len, 1);
-               if (!insn)
-                       return -ENOMEM;
-               insn->op = FILTER_OP_LOAD_S64;
-               memcpy(insn->data, &node->u.load.u.num, sizeof(int64_t));
-               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-               free(insn);
-               return ret;
-       }
-       case IR_DATA_FLOAT:
-       {
-               struct load_op *insn;
-               uint32_t insn_len = sizeof(struct load_op)
-                       + sizeof(struct literal_double);
-
-               insn = calloc(insn_len, 1);
-               if (!insn)
-                       return -ENOMEM;
-               insn->op = FILTER_OP_LOAD_DOUBLE;
-               memcpy(insn->data, &node->u.load.u.flt, sizeof(double));
-               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-               free(insn);
-               return ret;
-       }
-       case IR_DATA_EXPRESSION:
-               return visit_node_load_expression(ctx, node);
-       }
-}
-
-static
-int visit_node_unary(struct filter_parser_ctx *ctx, struct ir_op *node)
-{
-       int ret;
-       struct unary_op insn;
-
-       /* Visit child */
-       ret = recursive_visit_gen_bytecode(ctx, node->u.unary.child);
-       if (ret)
-               return ret;
-
-       /* Generate end of bytecode instruction */
-       switch (node->u.unary.type) {
-       case AST_UNARY_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] Unknown unary node type in %s\n",
-                       __func__);
-               return -EINVAL;
-       case AST_UNARY_PLUS:
-               /* Nothing to do. */
-               return 0;
-       case AST_UNARY_MINUS:
-               insn.op = FILTER_OP_UNARY_MINUS;
-               return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
-       case AST_UNARY_NOT:
-               insn.op = FILTER_OP_UNARY_NOT;
-               return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
-       case AST_UNARY_BIT_NOT:
-               insn.op = FILTER_OP_UNARY_BIT_NOT;
-               return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
-       }
-}
-
-/*
- * Binary comparator nesting is disallowed. This allows fitting into
- * only 2 registers.
- */
-static
-int visit_node_binary(struct filter_parser_ctx *ctx, struct ir_op *node)
-{
-       int ret;
-       struct binary_op insn;
-
-       /* Visit child */
-       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.left);
-       if (ret)
-               return ret;
-       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.right);
-       if (ret)
-               return ret;
-
-       switch (node->u.binary.type) {
-       case AST_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] Unknown unary node type in %s\n",
-                       __func__);
-               return -EINVAL;
-
-       case AST_OP_AND:
-       case AST_OP_OR:
-               fprintf(stderr, "[error] Unexpected logical node type in %s\n",
-                       __func__);
-               return -EINVAL;
-
-       case AST_OP_MUL:
-               insn.op = FILTER_OP_MUL;
-               break;
-       case AST_OP_DIV:
-               insn.op = FILTER_OP_DIV;
-               break;
-       case AST_OP_MOD:
-               insn.op = FILTER_OP_MOD;
-               break;
-       case AST_OP_PLUS:
-               insn.op = FILTER_OP_PLUS;
-               break;
-       case AST_OP_MINUS:
-               insn.op = FILTER_OP_MINUS;
-               break;
-       case AST_OP_BIT_RSHIFT:
-               insn.op = FILTER_OP_BIT_RSHIFT;
-               break;
-       case AST_OP_BIT_LSHIFT:
-               insn.op = FILTER_OP_BIT_LSHIFT;
-               break;
-       case AST_OP_BIT_AND:
-               insn.op = FILTER_OP_BIT_AND;
-               break;
-       case AST_OP_BIT_OR:
-               insn.op = FILTER_OP_BIT_OR;
-               break;
-       case AST_OP_BIT_XOR:
-               insn.op = FILTER_OP_BIT_XOR;
-               break;
-
-       case AST_OP_EQ:
-               insn.op = FILTER_OP_EQ;
-               break;
-       case AST_OP_NE:
-               insn.op = FILTER_OP_NE;
-               break;
-       case AST_OP_GT:
-               insn.op = FILTER_OP_GT;
-               break;
-       case AST_OP_LT:
-               insn.op = FILTER_OP_LT;
-               break;
-       case AST_OP_GE:
-               insn.op = FILTER_OP_GE;
-               break;
-       case AST_OP_LE:
-               insn.op = FILTER_OP_LE;
-               break;
-       }
-       return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
-}
-
-/*
- * A logical op always return a s64 (1 or 0).
- */
-static
-int visit_node_logical(struct filter_parser_ctx *ctx, struct ir_op *node)
-{
-       int ret;
-       struct logical_op insn;
-       uint16_t skip_offset_loc;
-       uint16_t target_loc;
-
-       /* Visit left child */
-       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.left);
-       if (ret)
-               return ret;
-       /* Cast to s64 if float or field ref */
-       if ((node->u.binary.left->data_type == IR_DATA_FIELD_REF
-                               || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
-                               || node->u.binary.left->data_type == IR_DATA_EXPRESSION)
-                       || node->u.binary.left->data_type == IR_DATA_FLOAT) {
-               struct cast_op cast_insn;
-
-               if (node->u.binary.left->data_type == IR_DATA_FIELD_REF
-                               || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
-                               || node->u.binary.left->data_type == IR_DATA_EXPRESSION) {
-                       cast_insn.op = FILTER_OP_CAST_TO_S64;
-               } else {
-                       cast_insn.op = FILTER_OP_CAST_DOUBLE_TO_S64;
-               }
-               ret = bytecode_push(&ctx->bytecode, &cast_insn,
-                                       1, sizeof(cast_insn));
-               if (ret)
-                       return ret;
-       }
-       switch (node->u.logical.type) {
-       default:
-               fprintf(stderr, "[error] Unknown node type in %s\n",
-                       __func__);
-               return -EINVAL;
-
-       case AST_OP_AND:
-               insn.op = FILTER_OP_AND;
-               break;
-       case AST_OP_OR:
-               insn.op = FILTER_OP_OR;
-               break;
-       }
-       insn.skip_offset = (uint16_t) -1UL;     /* Temporary */
-       ret = bytecode_push_logical(&ctx->bytecode, &insn, 1, sizeof(insn),
-                       &skip_offset_loc);
-       if (ret)
-               return ret;
-       /* Visit right child */
-       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.right);
-       if (ret)
-               return ret;
-       /* Cast to s64 if float or field ref */
-       if ((node->u.binary.right->data_type == IR_DATA_FIELD_REF
-                               || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
-                               || node->u.binary.right->data_type == IR_DATA_EXPRESSION)
-                       || node->u.binary.right->data_type == IR_DATA_FLOAT) {
-               struct cast_op cast_insn;
-
-               if (node->u.binary.right->data_type == IR_DATA_FIELD_REF
-                               || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
-                               || node->u.binary.right->data_type == IR_DATA_EXPRESSION) {
-                       cast_insn.op = FILTER_OP_CAST_TO_S64;
-               } else {
-                       cast_insn.op = FILTER_OP_CAST_DOUBLE_TO_S64;
-               }
-               ret = bytecode_push(&ctx->bytecode, &cast_insn,
-                                       1, sizeof(cast_insn));
-               if (ret)
-                       return ret;
-       }
-       /* We now know where the logical op can skip. */
-       target_loc = (uint16_t) bytecode_get_len(&ctx->bytecode->b);
-       ret = bytecode_patch(&ctx->bytecode,
-                       &target_loc,                    /* Offset to jump to */
-                       skip_offset_loc,                /* Where to patch */
-                       sizeof(uint16_t));
-       return ret;
-}
-
-/*
- * Postorder traversal of the tree. We need the children result before
- * we can evaluate the parent.
- */
-static
-int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
-               struct ir_op *node)
-{
-       switch (node->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] Unknown node type in %s\n",
-                       __func__);
-               return -EINVAL;
-
-       case IR_OP_ROOT:
-               return visit_node_root(ctx, node);
-       case IR_OP_LOAD:
-               return visit_node_load(ctx, node);
-       case IR_OP_UNARY:
-               return visit_node_unary(ctx, node);
-       case IR_OP_BINARY:
-               return visit_node_binary(ctx, node);
-       case IR_OP_LOGICAL:
-               return visit_node_logical(ctx, node);
-       }
-}
-
-LTTNG_HIDDEN
-void filter_bytecode_free(struct filter_parser_ctx *ctx)
-{
-       if (!ctx) {
-               return;
-       }
-
-       if (ctx->bytecode) {
-               free(ctx->bytecode);
-               ctx->bytecode = NULL;
-       }
-
-       if (ctx->bytecode_reloc) {
-               free(ctx->bytecode_reloc);
-               ctx->bytecode_reloc = NULL;
-       }
-}
-
-LTTNG_HIDDEN
-int filter_visitor_bytecode_generate(struct filter_parser_ctx *ctx)
-{
-       int ret;
-
-       ret = bytecode_init(&ctx->bytecode);
-       if (ret)
-               return ret;
-       ret = bytecode_init(&ctx->bytecode_reloc);
-       if (ret)
-               goto error;
-       ret = recursive_visit_gen_bytecode(ctx, ctx->ir_root);
-       if (ret)
-               goto error;
-
-       /* Finally, append symbol table to bytecode */
-       ctx->bytecode->b.reloc_table_offset = bytecode_get_len(&ctx->bytecode->b);
-       return bytecode_push(&ctx->bytecode, ctx->bytecode_reloc->b.data,
-                       1, bytecode_get_len(&ctx->bytecode_reloc->b));
-
-error:
-       filter_bytecode_free(ctx);
-       return ret;
-}
diff --git a/src/lib/lttng-ctl/filter/filter-visitor-generate-ir.c b/src/lib/lttng-ctl/filter/filter-visitor-generate-ir.c
deleted file mode 100644 (file)
index 11c6b61..0000000
+++ /dev/null
@@ -1,909 +0,0 @@
-/*
- * filter-visitor-generate-ir.c
- *
- * LTTng filter generate intermediate representation
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-#include <common/macros.h>
-#include <common/string-utils/string-utils.h>
-
-static
-struct ir_op *generate_ir_recursive(struct filter_parser_ctx *ctx,
-               struct filter_node *node, enum ir_side side);
-
-static
-struct ir_op *make_op_root(struct ir_op *child, enum ir_side side)
-{
-       struct ir_op *op;
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       switch (child->data_type) {
-       case IR_DATA_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] Unknown root child data type\n");
-               free(op);
-               return NULL;
-       case IR_DATA_STRING:
-               fprintf(stderr, "[error] String cannot be root data type\n");
-               free(op);
-               return NULL;
-       case IR_DATA_NUMERIC:
-       case IR_DATA_FIELD_REF:
-       case IR_DATA_GET_CONTEXT_REF:
-       case IR_DATA_EXPRESSION:
-               /* ok */
-               break;
-       }
-       op->op = IR_OP_ROOT;
-       op->side = side;
-       op->data_type = child->data_type;
-       op->signedness = child->signedness;
-       op->u.root.child = child;
-       return op;
-}
-
-static
-enum ir_load_string_type get_literal_string_type(const char *string)
-{
-       assert(string);
-
-       if (strutils_is_star_glob_pattern(string)) {
-               if (strutils_is_star_at_the_end_only_glob_pattern(string)) {
-                       return IR_LOAD_STRING_TYPE_GLOB_STAR_END;
-               }
-
-               return IR_LOAD_STRING_TYPE_GLOB_STAR;
-       }
-
-       return IR_LOAD_STRING_TYPE_PLAIN;
-}
-
-static
-struct ir_op *make_op_load_string(const char *string, enum ir_side side)
-{
-       struct ir_op *op;
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_LOAD;
-       op->data_type = IR_DATA_STRING;
-       op->signedness = IR_SIGN_UNKNOWN;
-       op->side = side;
-       op->u.load.u.string.type = get_literal_string_type(string);
-       op->u.load.u.string.value = strdup(string);
-       if (!op->u.load.u.string.value) {
-               free(op);
-               return NULL;
-       }
-       return op;
-}
-
-static
-struct ir_op *make_op_load_numeric(int64_t v, enum ir_side side)
-{
-       struct ir_op *op;
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_LOAD;
-       op->data_type = IR_DATA_NUMERIC;
-       /* TODO: for now, all numeric values are signed */
-       op->signedness = IR_SIGNED;
-       op->side = side;
-       op->u.load.u.num = v;
-       return op;
-}
-
-static
-struct ir_op *make_op_load_float(double v, enum ir_side side)
-{
-       struct ir_op *op;
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_LOAD;
-       op->data_type = IR_DATA_FLOAT;
-       op->signedness = IR_SIGN_UNKNOWN;
-       op->side = side;
-       op->u.load.u.flt = v;
-       return op;
-}
-
-static
-void free_load_expression(struct ir_load_expression *load_expression)
-{
-       struct ir_load_expression_op *exp_op;
-
-       if (!load_expression)
-               return;
-       exp_op = load_expression->child;
-       for (;;) {
-               struct ir_load_expression_op *prev_exp_op;
-
-               if (!exp_op)
-                       break;
-               switch (exp_op->type) {
-               case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
-               case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
-               case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
-               case IR_LOAD_EXPRESSION_GET_INDEX:
-               case IR_LOAD_EXPRESSION_LOAD_FIELD:
-                       break;
-               case IR_LOAD_EXPRESSION_GET_SYMBOL:
-                       free(exp_op->u.symbol);
-                       break;
-               }
-               prev_exp_op = exp_op;
-               exp_op = exp_op->next;
-               free(prev_exp_op);
-       }
-       free(load_expression);
-}
-
-/*
- * Returns the first node of the chain, after initializing the next
- * pointers.
- */
-static
-struct filter_node *load_expression_get_forward_chain(struct filter_node *node)
-{
-       struct filter_node *prev_node;
-
-       for (;;) {
-               assert(node->type == NODE_EXPRESSION);
-               prev_node = node;
-               node = node->u.expression.prev;
-               if (!node) {
-                       break;
-               }
-               node->u.expression.next = prev_node;
-       }
-       return prev_node;
-}
-
-static
-struct ir_load_expression *create_load_expression(struct filter_node *node)
-{
-       struct ir_load_expression *load_exp;
-       struct ir_load_expression_op *load_exp_op, *prev_op;
-       const char *str;
-
-       /* Get forward chain. */
-       node = load_expression_get_forward_chain(node);
-       if (!node)
-               return NULL;
-       load_exp = calloc(sizeof(struct ir_load_expression), 1);
-       if (!load_exp)
-               return NULL;
-
-       /* Root */
-       load_exp_op = calloc(sizeof(struct ir_load_expression_op), 1);
-       if (!load_exp_op)
-               goto error;
-       load_exp->child = load_exp_op;
-       str = node->u.expression.u.string;
-       if (!strcmp(str, "$ctx")) {
-               load_exp_op->type = IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT;
-               node = node->u.expression.next;
-               if (!node) {
-                       fprintf(stderr, "[error] Expecting identifier after \'%s\'\n", str);
-                       goto error;
-               }
-               str = node->u.expression.u.string;
-       } else if (!strcmp(str, "$app")) {
-               load_exp_op->type = IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT;
-               node = node->u.expression.next;
-               if (!node) {
-                       fprintf(stderr, "[error] Expecting identifier after \'%s\'\n", str);
-                       goto error;
-               }
-               str = node->u.expression.u.string;
-       } else if (str[0] == '$') {
-               fprintf(stderr, "[error] Unexpected identifier \'%s\'\n", str);
-               goto error;
-       } else {
-               load_exp_op->type = IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT;
-       }
-
-       for (;;) {
-               struct filter_node *bracket_node;
-
-               prev_op = load_exp_op;
-               load_exp_op = calloc(sizeof(struct ir_load_expression_op), 1);
-               if (!load_exp_op)
-                       goto error;
-               prev_op->next = load_exp_op;
-               load_exp_op->type = IR_LOAD_EXPRESSION_GET_SYMBOL;
-               load_exp_op->u.symbol = strdup(str);
-               if (!load_exp_op->u.symbol)
-                       goto error;
-
-               /* Explore brackets from current node. */
-               for (bracket_node = node->u.expression.next_bracket;
-                               bracket_node != NULL;
-                               bracket_node = bracket_node->u.expression.next_bracket) {
-                       prev_op = load_exp_op;
-                       load_exp_op = calloc(sizeof(struct ir_load_expression_op), 1);
-                       if (!load_exp_op)
-                               goto error;
-                       prev_op->next = load_exp_op;
-                       load_exp_op->type = IR_LOAD_EXPRESSION_GET_INDEX;
-                       load_exp_op->u.index = bracket_node->u.expression.u.constant;
-               }
-               /* Go to next chain element. */
-               node = node->u.expression.next;
-               if (!node)
-                       break;
-               str = node->u.expression.u.string;
-       }
-       /* Add final load field */
-       prev_op = load_exp_op;
-       load_exp_op = calloc(sizeof(struct ir_load_expression_op), 1);
-       if (!load_exp_op)
-               goto error;
-       prev_op->next = load_exp_op;
-       load_exp_op->type = IR_LOAD_EXPRESSION_LOAD_FIELD;
-       return load_exp;
-
-error:
-       free_load_expression(load_exp);
-       return NULL;
-}
-
-static
-struct ir_op *make_op_load_expression(struct filter_node *node,
-               enum ir_side side)
-{
-       struct ir_op *op;
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_LOAD;
-       op->data_type = IR_DATA_EXPRESSION;
-       op->signedness = IR_SIGN_DYN;
-       op->side = side;
-       op->u.load.u.expression = create_load_expression(node);
-       if (!op->u.load.u.expression) {
-               goto error;
-       }
-       return op;
-
-error:
-       free_load_expression(op->u.load.u.expression);
-       free(op);
-       return NULL;
-}
-
-static
-struct ir_op *make_op_unary(enum unary_op_type unary_op_type,
-                       const char *op_str, enum ir_op_signedness signedness,
-                       struct ir_op *child, enum ir_side side)
-{
-       struct ir_op *op = NULL;
-
-       if (child->data_type == IR_DATA_STRING) {
-               fprintf(stderr, "[error] unary operation '%s' not allowed on string literal\n", op_str);
-               goto error;
-       }
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_UNARY;
-       op->data_type = child->data_type;
-       op->signedness = signedness;
-       op->side = side;
-       op->u.unary.type = unary_op_type;
-       op->u.unary.child = child;
-       return op;
-
-error:
-       free(op);
-       return NULL;
-}
-
-/*
- * unary + is pretty much useless.
- */
-static
-struct ir_op *make_op_unary_plus(struct ir_op *child, enum ir_side side)
-{
-       return make_op_unary(AST_UNARY_PLUS, "+", child->signedness,
-                       child, side);
-}
-
-static
-struct ir_op *make_op_unary_minus(struct ir_op *child, enum ir_side side)
-{
-       return make_op_unary(AST_UNARY_MINUS, "-", child->signedness,
-                       child, side);
-}
-
-static
-struct ir_op *make_op_unary_not(struct ir_op *child, enum ir_side side)
-{
-       return make_op_unary(AST_UNARY_NOT, "!", child->signedness,
-                       child, side);
-}
-
-static
-struct ir_op *make_op_unary_bit_not(struct ir_op *child, enum ir_side side)
-{
-       return make_op_unary(AST_UNARY_BIT_NOT, "~", child->signedness,
-                       child, side);
-}
-
-static
-struct ir_op *make_op_binary_compare(enum op_type bin_op_type,
-               const char *op_str, struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       struct ir_op *op = NULL;
-
-       if (left->data_type == IR_DATA_UNKNOWN
-               || right->data_type == IR_DATA_UNKNOWN) {
-               fprintf(stderr, "[error] binary operation '%s' has unknown operand type\n", op_str);
-               goto error;
-
-       }
-       if ((left->data_type == IR_DATA_STRING
-               && (right->data_type == IR_DATA_NUMERIC || right->data_type == IR_DATA_FLOAT))
-               || ((left->data_type == IR_DATA_NUMERIC || left->data_type == IR_DATA_FLOAT) &&
-                       right->data_type == IR_DATA_STRING)) {
-               fprintf(stderr, "[error] binary operation '%s' operand type mismatch\n", op_str);
-               goto error;
-       }
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_BINARY;
-       op->u.binary.type = bin_op_type;
-       op->u.binary.left = left;
-       op->u.binary.right = right;
-
-       /* we return a boolean, represented as signed numeric */
-       op->data_type = IR_DATA_NUMERIC;
-       op->signedness = IR_SIGNED;
-       op->side = side;
-
-       return op;
-
-error:
-       free(op);
-       return NULL;
-}
-
-static
-struct ir_op *make_op_binary_eq(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_compare(AST_OP_EQ, "==", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_ne(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_compare(AST_OP_NE, "!=", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_gt(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_compare(AST_OP_GT, ">", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_lt(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_compare(AST_OP_LT, "<", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_ge(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_compare(AST_OP_GE, ">=", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_le(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_compare(AST_OP_LE, "<=", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_logical(enum op_type bin_op_type,
-               const char *op_str, struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       struct ir_op *op = NULL;
-
-       if (left->data_type == IR_DATA_UNKNOWN
-               || right->data_type == IR_DATA_UNKNOWN) {
-               fprintf(stderr, "[error] binary operation '%s' has unknown operand type\n", op_str);
-               goto error;
-
-       }
-       if (left->data_type == IR_DATA_STRING
-               || right->data_type == IR_DATA_STRING) {
-               fprintf(stderr, "[error] logical binary operation '%s' cannot have string operand\n", op_str);
-               goto error;
-       }
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_LOGICAL;
-       op->u.binary.type = bin_op_type;
-       op->u.binary.left = left;
-       op->u.binary.right = right;
-
-       /* we return a boolean, represented as signed numeric */
-       op->data_type = IR_DATA_NUMERIC;
-       op->signedness = IR_SIGNED;
-       op->side = side;
-
-       return op;
-
-error:
-       free(op);
-       return NULL;
-}
-
-static
-struct ir_op *make_op_binary_bitwise(enum op_type bin_op_type,
-               const char *op_str, struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       struct ir_op *op = NULL;
-
-       if (left->data_type == IR_DATA_UNKNOWN
-               || right->data_type == IR_DATA_UNKNOWN) {
-               fprintf(stderr, "[error] bitwise binary operation '%s' has unknown operand type\n", op_str);
-               goto error;
-
-       }
-       if (left->data_type == IR_DATA_STRING
-               || right->data_type == IR_DATA_STRING) {
-               fprintf(stderr, "[error] bitwise binary operation '%s' cannot have string operand\n", op_str);
-               goto error;
-       }
-       if (left->data_type == IR_DATA_FLOAT
-               || right->data_type == IR_DATA_FLOAT) {
-               fprintf(stderr, "[error] bitwise binary operation '%s' cannot have floating point operand\n", op_str);
-               goto error;
-       }
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_BINARY;
-       op->u.binary.type = bin_op_type;
-       op->u.binary.left = left;
-       op->u.binary.right = right;
-
-       /* we return a signed numeric */
-       op->data_type = IR_DATA_NUMERIC;
-       op->signedness = IR_SIGNED;
-       op->side = side;
-
-       return op;
-
-error:
-       free(op);
-       return NULL;
-}
-
-static
-struct ir_op *make_op_binary_logical_and(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_logical(AST_OP_AND, "&&", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_logical_or(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_logical(AST_OP_OR, "||", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_bitwise_rshift(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_bitwise(AST_OP_BIT_RSHIFT, ">>", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_bitwise_lshift(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_bitwise(AST_OP_BIT_LSHIFT, "<<", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_bitwise_and(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_bitwise(AST_OP_BIT_AND, "&", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_bitwise_or(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_bitwise(AST_OP_BIT_OR, "|", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_bitwise_xor(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_bitwise(AST_OP_BIT_XOR, "^", left, right, side);
-}
-
-static
-void filter_free_ir_recursive(struct ir_op *op)
-{
-       if (!op)
-               return;
-       switch (op->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] Unknown op type in %s\n",
-                       __func__);
-               break;
-       case IR_OP_ROOT:
-               filter_free_ir_recursive(op->u.root.child);
-               break;
-       case IR_OP_LOAD:
-               switch (op->data_type) {
-               case IR_DATA_STRING:
-                       free(op->u.load.u.string.value);
-                       break;
-               case IR_DATA_FIELD_REF:         /* fall-through */
-               case IR_DATA_GET_CONTEXT_REF:
-                       free(op->u.load.u.ref);
-                       break;
-               case IR_DATA_EXPRESSION:
-                       free_load_expression(op->u.load.u.expression);
-               default:
-                       break;
-               }
-               break;
-       case IR_OP_UNARY:
-               filter_free_ir_recursive(op->u.unary.child);
-               break;
-       case IR_OP_BINARY:
-               filter_free_ir_recursive(op->u.binary.left);
-               filter_free_ir_recursive(op->u.binary.right);
-               break;
-       case IR_OP_LOGICAL:
-               filter_free_ir_recursive(op->u.logical.left);
-               filter_free_ir_recursive(op->u.logical.right);
-               break;
-       }
-       free(op);
-}
-
-static
-struct ir_op *make_expression(struct filter_parser_ctx *ctx,
-               struct filter_node *node, enum ir_side side)
-{
-       switch (node->u.expression.type) {
-       case AST_EXP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown expression type\n", __func__);
-               return NULL;
-
-       case AST_EXP_STRING:
-               return make_op_load_string(node->u.expression.u.string, side);
-       case AST_EXP_CONSTANT:
-               return make_op_load_numeric(node->u.expression.u.constant,
-                                       side);
-       case AST_EXP_FLOAT_CONSTANT:
-               return make_op_load_float(node->u.expression.u.float_constant,
-                                       side);
-       case AST_EXP_IDENTIFIER:
-       case AST_EXP_GLOBAL_IDENTIFIER:
-               return make_op_load_expression(node, side);
-       case AST_EXP_NESTED:
-               return generate_ir_recursive(ctx, node->u.expression.u.child,
-                                       side);
-       }
-}
-
-static
-struct ir_op *make_op(struct filter_parser_ctx *ctx,
-               struct filter_node *node, enum ir_side side)
-{
-       struct ir_op *op = NULL, *lchild, *rchild;
-       const char *op_str = "?";
-
-       switch (node->u.op.type) {
-       case AST_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown binary op type\n", __func__);
-               return NULL;
-
-       /*
-        * The following binary operators other than comparators and
-        * logical and/or are not supported yet.
-        */
-       case AST_OP_MUL:
-               op_str = "*";
-               goto error_not_supported;
-       case AST_OP_DIV:
-               op_str = "/";
-               goto error_not_supported;
-       case AST_OP_MOD:
-               op_str = "%";
-               goto error_not_supported;
-       case AST_OP_PLUS:
-               op_str = "+";
-               goto error_not_supported;
-       case AST_OP_MINUS:
-               op_str = "-";
-               goto error_not_supported;
-
-       case AST_OP_BIT_RSHIFT:
-       case AST_OP_BIT_LSHIFT:
-       case AST_OP_BIT_AND:
-       case AST_OP_BIT_OR:
-       case AST_OP_BIT_XOR:
-               lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
-               if (!lchild)
-                       return NULL;
-               rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_RIGHT);
-               if (!rchild) {
-                       filter_free_ir_recursive(lchild);
-                       return NULL;
-               }
-               break;
-
-       case AST_OP_EQ:
-       case AST_OP_NE:
-       case AST_OP_GT:
-       case AST_OP_LT:
-       case AST_OP_GE:
-       case AST_OP_LE:
-               lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
-               if (!lchild)
-                       return NULL;
-               rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_RIGHT);
-               if (!rchild) {
-                       filter_free_ir_recursive(lchild);
-                       return NULL;
-               }
-               break;
-
-       case AST_OP_AND:
-       case AST_OP_OR:
-               /*
-                * Both children considered as left, since we need to
-                * populate R0.
-                */
-               lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
-               if (!lchild)
-                       return NULL;
-               rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_LEFT);
-               if (!rchild) {
-                       filter_free_ir_recursive(lchild);
-                       return NULL;
-               }
-               break;
-       }
-
-       switch (node->u.op.type) {
-       case AST_OP_AND:
-               op = make_op_binary_logical_and(lchild, rchild, side);
-               break;
-       case AST_OP_OR:
-               op = make_op_binary_logical_or(lchild, rchild, side);
-               break;
-       case AST_OP_EQ:
-               op = make_op_binary_eq(lchild, rchild, side);
-               break;
-       case AST_OP_NE:
-               op = make_op_binary_ne(lchild, rchild, side);
-               break;
-       case AST_OP_GT:
-               op = make_op_binary_gt(lchild, rchild, side);
-               break;
-       case AST_OP_LT:
-               op = make_op_binary_lt(lchild, rchild, side);
-               break;
-       case AST_OP_GE:
-               op = make_op_binary_ge(lchild, rchild, side);
-               break;
-       case AST_OP_LE:
-               op = make_op_binary_le(lchild, rchild, side);
-               break;
-       case AST_OP_BIT_RSHIFT:
-               op = make_op_binary_bitwise_rshift(lchild, rchild, side);
-               break;
-       case AST_OP_BIT_LSHIFT:
-               op = make_op_binary_bitwise_lshift(lchild, rchild, side);
-               break;
-       case AST_OP_BIT_AND:
-               op = make_op_binary_bitwise_and(lchild, rchild, side);
-               break;
-       case AST_OP_BIT_OR:
-               op = make_op_binary_bitwise_or(lchild, rchild, side);
-               break;
-       case AST_OP_BIT_XOR:
-               op = make_op_binary_bitwise_xor(lchild, rchild, side);
-               break;
-       default:
-               break;
-       }
-
-       if (!op) {
-               filter_free_ir_recursive(rchild);
-               filter_free_ir_recursive(lchild);
-       }
-       return op;
-
-error_not_supported:
-       fprintf(stderr, "[error] %s: binary operation '%s' not supported\n",
-               __func__, op_str);
-       return NULL;
-}
-
-static
-struct ir_op *make_unary_op(struct filter_parser_ctx *ctx,
-               struct filter_node *node, enum ir_side side)
-{
-       switch (node->u.unary_op.type) {
-       case AST_UNARY_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown unary op type\n", __func__);
-               return NULL;
-
-       case AST_UNARY_PLUS:
-       {
-               struct ir_op *op, *child;
-
-               child = generate_ir_recursive(ctx, node->u.unary_op.child,
-                                       side);
-               if (!child)
-                       return NULL;
-               op = make_op_unary_plus(child, side);
-               if (!op) {
-                       filter_free_ir_recursive(child);
-                       return NULL;
-               }
-               return op;
-       }
-       case AST_UNARY_MINUS:
-       {
-               struct ir_op *op, *child;
-
-               child = generate_ir_recursive(ctx, node->u.unary_op.child,
-                                       side);
-               if (!child)
-                       return NULL;
-               op = make_op_unary_minus(child, side);
-               if (!op) {
-                       filter_free_ir_recursive(child);
-                       return NULL;
-               }
-               return op;
-       }
-       case AST_UNARY_NOT:
-       {
-               struct ir_op *op, *child;
-
-               child = generate_ir_recursive(ctx, node->u.unary_op.child,
-                                       side);
-               if (!child)
-                       return NULL;
-               op = make_op_unary_not(child, side);
-               if (!op) {
-                       filter_free_ir_recursive(child);
-                       return NULL;
-               }
-               return op;
-       }
-       case AST_UNARY_BIT_NOT:
-       {
-               struct ir_op *op, *child;
-
-               child = generate_ir_recursive(ctx, node->u.unary_op.child,
-                                       side);
-               if (!child)
-                       return NULL;
-               op = make_op_unary_bit_not(child, side);
-               if (!op) {
-                       filter_free_ir_recursive(child);
-                       return NULL;
-               }
-               return op;
-       }
-       }
-
-       return NULL;
-}
-
-static
-struct ir_op *generate_ir_recursive(struct filter_parser_ctx *ctx,
-               struct filter_node *node, enum ir_side side)
-{
-       switch (node->type) {
-       case NODE_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown node type\n", __func__);
-               return NULL;
-
-       case NODE_ROOT:
-       {
-               struct ir_op *op, *child;
-
-               child = generate_ir_recursive(ctx, node->u.root.child,
-                                       side);
-               if (!child)
-                       return NULL;
-               op = make_op_root(child, side);
-               if (!op) {
-                       filter_free_ir_recursive(child);
-                       return NULL;
-               }
-               return op;
-       }
-       case NODE_EXPRESSION:
-               return make_expression(ctx, node, side);
-       case NODE_OP:
-               return make_op(ctx, node, side);
-       case NODE_UNARY_OP:
-               return make_unary_op(ctx, node, side);
-       }
-       return 0;
-}
-
-LTTNG_HIDDEN
-void filter_ir_free(struct filter_parser_ctx *ctx)
-{
-       filter_free_ir_recursive(ctx->ir_root);
-       ctx->ir_root = NULL;
-}
-
-LTTNG_HIDDEN
-int filter_visitor_ir_generate(struct filter_parser_ctx *ctx)
-{
-       struct ir_op *op;
-
-       op = generate_ir_recursive(ctx, &ctx->ast->root, IR_LEFT);
-       if (!op) {
-               return -EINVAL;
-       }
-       ctx->ir_root = op;
-       return 0;
-}
diff --git a/src/lib/lttng-ctl/filter/filter-visitor-ir-check-binary-comparator.c b/src/lib/lttng-ctl/filter/filter-visitor-ir-check-binary-comparator.c
deleted file mode 100644 (file)
index bcbb69e..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * filter-visitor-ir-check-binary-comparator.c
- *
- * LTTng filter IR check binary comparator
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-static
-int check_bin_comparator(struct ir_op *node)
-{
-       switch (node->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
-               return -EINVAL;
-
-       case IR_OP_ROOT:
-               return check_bin_comparator(node->u.root.child);
-       case IR_OP_LOAD:
-               return 0;
-       case IR_OP_UNARY:
-               return check_bin_comparator(node->u.unary.child);
-       case IR_OP_BINARY:
-       {
-               int ret;
-
-               if (node->u.binary.left->data_type == IR_DATA_STRING
-                               || node->u.binary.right->data_type
-                                       == IR_DATA_STRING) {
-                       if (node->u.binary.type != AST_OP_EQ
-                                       && node->u.binary.type != AST_OP_NE) {
-                               fprintf(stderr, "[error] Only '==' and '!=' comparators are allowed for strings\n");
-                               return -EINVAL;
-                       }
-               }
-
-               ret = check_bin_comparator(node->u.binary.left);
-               if (ret)
-                       return ret;
-               return check_bin_comparator(node->u.binary.right);
-       }
-       case IR_OP_LOGICAL:
-       {
-               int ret;
-
-               ret = check_bin_comparator(node->u.logical.left);
-               if (ret)
-                       return ret;
-               return check_bin_comparator(node->u.logical.right);
-       }
-       }
-}
-
-int filter_visitor_ir_check_binary_comparator(struct filter_parser_ctx *ctx)
-{
-       return check_bin_comparator(ctx->ir_root);
-}
diff --git a/src/lib/lttng-ctl/filter/filter-visitor-ir-check-binary-op-nesting.c b/src/lib/lttng-ctl/filter/filter-visitor-ir-check-binary-op-nesting.c
deleted file mode 100644 (file)
index 04a5fbd..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * filter-visitor-ir-check-binary-op-nesting.c
- *
- * LTTng filter IR check binary op nesting
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-#include <common/macros.h>
-
-static
-int check_bin_op_nesting_recursive(struct ir_op *node, int nesting)
-{
-       switch (node->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
-               return -EINVAL;
-
-       case IR_OP_ROOT:
-               return check_bin_op_nesting_recursive(node->u.root.child,
-                               nesting);
-       case IR_OP_LOAD:
-               return 0;
-       case IR_OP_UNARY:
-               return check_bin_op_nesting_recursive(node->u.unary.child,
-                               nesting);
-       case IR_OP_BINARY:
-       {
-               int ret;
-
-               ret = check_bin_op_nesting_recursive(node->u.binary.left,
-                               nesting + 1);
-               if (ret)
-                       return ret;
-               return check_bin_op_nesting_recursive(node->u.binary.right,
-                               nesting + 1);
-       }
-       case IR_OP_LOGICAL:
-       {
-               int ret;
-
-               ret = check_bin_op_nesting_recursive(node->u.logical.left,
-                               nesting);
-               if (ret)
-                       return ret;
-               return check_bin_op_nesting_recursive(node->u.logical.right,
-                               nesting);
-       }
-       }
-}
-
-LTTNG_HIDDEN
-int filter_visitor_ir_check_binary_op_nesting(struct filter_parser_ctx *ctx)
-{
-       return check_bin_op_nesting_recursive(ctx->ir_root, 0);
-}
diff --git a/src/lib/lttng-ctl/filter/filter-visitor-ir-normalize-glob-patterns.c b/src/lib/lttng-ctl/filter/filter-visitor-ir-normalize-glob-patterns.c
deleted file mode 100644 (file)
index 5e2778e..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * filter-visitor-ir-normalize-glob-patterns.c
- *
- * LTTng filter IR normalize string
- *
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-
-#include <common/macros.h>
-#include <common/string-utils/string-utils.h>
-
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-static
-int normalize_glob_patterns(struct ir_op *node)
-{
-       switch (node->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
-               return -EINVAL;
-
-       case IR_OP_ROOT:
-               return normalize_glob_patterns(node->u.root.child);
-       case IR_OP_LOAD:
-       {
-               if (node->data_type == IR_DATA_STRING) {
-                       enum ir_load_string_type type =
-                               node->u.load.u.string.type;
-                       if (type == IR_LOAD_STRING_TYPE_GLOB_STAR_END ||
-                                       type == IR_LOAD_STRING_TYPE_GLOB_STAR) {
-                               assert(node->u.load.u.string.value);
-                               strutils_normalize_star_glob_pattern(
-                                       node->u.load.u.string.value);
-                       }
-               }
-
-               return 0;
-       }
-       case IR_OP_UNARY:
-               return normalize_glob_patterns(node->u.unary.child);
-       case IR_OP_BINARY:
-       {
-               int ret = normalize_glob_patterns(node->u.binary.left);
-
-               if (ret)
-                       return ret;
-               return normalize_glob_patterns(node->u.binary.right);
-       }
-       case IR_OP_LOGICAL:
-       {
-               int ret;
-
-               ret = normalize_glob_patterns(node->u.logical.left);
-               if (ret)
-                       return ret;
-               return normalize_glob_patterns(node->u.logical.right);
-       }
-       }
-}
-
-/*
- * This function normalizes all the globbing literal strings with
- * utils_normalize_glob_pattern(). See the documentation of
- * utils_normalize_glob_pattern() for more details.
- */
-LTTNG_HIDDEN
-int filter_visitor_ir_normalize_glob_patterns(struct filter_parser_ctx *ctx)
-{
-       return normalize_glob_patterns(ctx->ir_root);
-}
diff --git a/src/lib/lttng-ctl/filter/filter-visitor-ir-validate-globbing.c b/src/lib/lttng-ctl/filter/filter-visitor-ir-validate-globbing.c
deleted file mode 100644 (file)
index 3e749a4..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * filter-visitor-ir-validate-globbing.c
- *
- * LTTng filter IR validate globbing
- *
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-
-#include <common/macros.h>
-
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-static
-int validate_globbing(struct ir_op *node)
-{
-       int ret;
-
-       switch (node->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
-               return -EINVAL;
-
-       case IR_OP_ROOT:
-               return validate_globbing(node->u.root.child);
-       case IR_OP_LOAD:
-               return 0;
-       case IR_OP_UNARY:
-               return validate_globbing(node->u.unary.child);
-       case IR_OP_BINARY:
-       {
-               struct ir_op *left = node->u.binary.left;
-               struct ir_op *right = node->u.binary.right;
-
-               if (left->op == IR_OP_LOAD && right->op == IR_OP_LOAD &&
-                               left->data_type == IR_DATA_STRING &&
-                               right->data_type == IR_DATA_STRING) {
-                       /* Test 1. */
-                       if (left->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR &&
-                                       right->u.load.u.string.type != IR_LOAD_STRING_TYPE_PLAIN) {
-                               fprintf(stderr, "[error] Cannot compare two globbing patterns\n");
-                               return -1;
-                       }
-
-                       if (right->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR &&
-                                       left->u.load.u.string.type != IR_LOAD_STRING_TYPE_PLAIN) {
-                               fprintf(stderr, "[error] Cannot compare two globbing patterns\n");
-                               return -1;
-                       }
-               }
-
-               if ((left->op == IR_OP_LOAD && left->data_type == IR_DATA_STRING) ||
-                               (right->op == IR_OP_LOAD && right->data_type == IR_DATA_STRING)) {
-                       if ((left->op == IR_OP_LOAD && left->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR) ||
-                                       (right->op == IR_OP_LOAD && right->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR)) {
-                               /* Test 2. */
-                               if (node->u.binary.type != AST_OP_EQ &&
-                                               node->u.binary.type != AST_OP_NE) {
-                                       fprintf(stderr, "[error] Only the `==` and `!=` operators are allowed with a globbing pattern\n");
-                                       return -1;
-                               }
-                       }
-               }
-
-               ret = validate_globbing(left);
-               if (ret) {
-                       return ret;
-               }
-
-               return validate_globbing(right);
-       }
-       case IR_OP_LOGICAL:
-               ret = validate_globbing(node->u.logical.left);
-               if (ret)
-                       return ret;
-               return validate_globbing(node->u.logical.right);
-       }
-}
-
-/*
- * This function recursively validates that:
- *
- * 1. When there's a binary operation between two literal strings,
- *    if one of them has the IR_LOAD_STRING_TYPE_GLOB_STAR type,
- *    the other one has the IR_LOAD_STRING_TYPE_PLAIN type.
- *
- *    In other words, you cannot compare two globbing patterns, except
- *    for two globbing patterns with only a star at the end for backward
- *    compatibility reasons.
- *
- * 2. When there's a binary operation between two literal strings, if
- *    one of them is a (full) star globbing pattern, the binary
- *    operation is either == or !=.
- */
-LTTNG_HIDDEN
-int filter_visitor_ir_validate_globbing(struct filter_parser_ctx *ctx)
-{
-       return validate_globbing(ctx->ir_root);
-}
diff --git a/src/lib/lttng-ctl/filter/filter-visitor-ir-validate-string.c b/src/lib/lttng-ctl/filter/filter-visitor-ir-validate-string.c
deleted file mode 100644 (file)
index 1df83b0..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * filter-visitor-ir-validate-string.c
- *
- * LTTng filter IR validate string
- *
- * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-
-#include <common/macros.h>
-
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-enum parse_char_result {
-       PARSE_CHAR_UNKNOWN = -2,
-       PARSE_CHAR_WILDCARD = -1,
-       PARSE_CHAR_NORMAL = 0,
-};
-
-static
-enum parse_char_result parse_char(const char **p)
-{
-       switch (**p) {
-       case '\\':
-               (*p)++;
-               switch (**p) {
-               case '\\':
-               case '*':
-                       return PARSE_CHAR_NORMAL;
-               default:
-                       return PARSE_CHAR_UNKNOWN;
-               }
-       case '*':
-               return PARSE_CHAR_WILDCARD;
-       default:
-               return PARSE_CHAR_NORMAL;
-       }
-}
-
-static
-int validate_string(struct ir_op *node)
-{
-       switch (node->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
-               return -EINVAL;
-
-       case IR_OP_ROOT:
-               return validate_string(node->u.root.child);
-       case IR_OP_LOAD:
-       {
-               int ret = 0;
-
-               if (node->data_type == IR_DATA_STRING) {
-                       const char *str;
-
-                       assert(node->u.load.u.string.value);
-                       str = node->u.load.u.string.value;
-
-                       for (;;) {
-                               enum parse_char_result res;
-
-                               if (!(*str)) {
-                                       break;
-                               }
-
-                               res = parse_char(&str);
-                               str++;
-
-                               switch (res) {
-                               case PARSE_CHAR_UNKNOWN:
-                                       ret = -EINVAL;
-                                       fprintf(stderr,
-                                               "Unsupported escape character detected.\n");
-                                       goto end_load;
-                               case PARSE_CHAR_NORMAL:
-                               default:
-                                       break;
-                               }
-                       }
-               }
-end_load:
-               return ret;
-       }
-       case IR_OP_UNARY:
-               return validate_string(node->u.unary.child);
-       case IR_OP_BINARY:
-       {
-               int ret = validate_string(node->u.binary.left);
-
-               if (ret)
-                       return ret;
-               return validate_string(node->u.binary.right);
-       }
-       case IR_OP_LOGICAL:
-       {
-               int ret;
-
-               ret = validate_string(node->u.logical.left);
-               if (ret)
-                       return ret;
-               return validate_string(node->u.logical.right);
-       }
-       }
-}
-
-LTTNG_HIDDEN
-int filter_visitor_ir_validate_string(struct filter_parser_ctx *ctx)
-{
-       return validate_string(ctx->ir_root);
-}
diff --git a/src/lib/lttng-ctl/filter/filter-visitor-xml.c b/src/lib/lttng-ctl/filter/filter-visitor-xml.c
deleted file mode 100644 (file)
index d5ff0c1..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * filter-visitor-xml.c
- *
- * LTTng filter XML pretty printer visitor
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-
-#include <common/macros.h>
-
-#define fprintf_dbg(fd, fmt, args...)  fprintf(fd, "%s: " fmt, __func__, ## args)
-
-static
-int recursive_visit_print(struct filter_node *node, FILE *stream, int indent);
-
-static
-void print_tabs(FILE *fd, int depth)
-{
-       int i;
-
-       for (i = 0; i < depth; i++)
-               fprintf(fd, "\t");
-}
-
-static
-int recursive_visit_print_expression(struct filter_node *node,
-               FILE *stream, int indent)
-{
-       struct filter_node *iter_node;
-
-       if (!node) {
-               fprintf(stderr, "[error] %s: NULL child\n", __func__);
-               return -EINVAL;
-       }
-       switch (node->u.expression.type) {
-       case AST_EXP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown expression\n", __func__);
-               return -EINVAL;
-       case AST_EXP_STRING:
-               print_tabs(stream, indent);
-               fprintf(stream, "<string value=\"%s\"/>\n",
-                       node->u.expression.u.string);
-               break;
-       case AST_EXP_CONSTANT:
-               print_tabs(stream, indent);
-               fprintf(stream, "<constant value=\"%" PRIu64 "\"/>\n",
-                       node->u.expression.u.constant);
-               break;
-       case AST_EXP_FLOAT_CONSTANT:
-               print_tabs(stream, indent);
-               fprintf(stream, "<float_constant value=\"%lg\"/>\n",
-                       node->u.expression.u.float_constant);
-               break;
-       case AST_EXP_IDENTIFIER:                /* fall-through */
-       case AST_EXP_GLOBAL_IDENTIFIER:
-               print_tabs(stream, indent);
-               fprintf(stream, "<%s value=\"%s\"/>\n",
-                       node->u.expression.type == AST_EXP_IDENTIFIER ?
-                               "identifier" : "global_identifier",
-                       node->u.expression.u.identifier);
-               iter_node = node->u.expression.next;
-               while (iter_node) {
-                       print_tabs(stream, indent);
-                       fprintf(stream, "<bracket>\n");
-                       if (recursive_visit_print_expression(iter_node,
-                                       stream, indent + 1)) {
-                               return -EINVAL;
-                       }
-                       print_tabs(stream, indent);
-                       fprintf(stream, "</bracket>\n");
-                       iter_node = iter_node->u.expression.next;
-
-               }
-               break;
-       case AST_EXP_NESTED:
-               return recursive_visit_print(node->u.expression.u.child,
-                               stream, indent + 1);
-       }
-       return 0;
-}
-
-
-static
-int recursive_visit_print(struct filter_node *node, FILE *stream, int indent)
-{
-       int ret;
-
-       if (!node) {
-               fprintf(stderr, "[error] %s: NULL child\n", __func__);
-               return -EINVAL;
-       }
-       switch (node->type) {
-       case NODE_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown node type\n", __func__);
-               return -EINVAL;
-       case NODE_ROOT:
-               print_tabs(stream, indent);
-               fprintf(stream, "<root>\n");
-               ret = recursive_visit_print(node->u.root.child, stream,
-                                       indent + 1);
-               print_tabs(stream, indent);
-               fprintf(stream, "</root>\n");
-               return ret;
-       case NODE_EXPRESSION:
-               print_tabs(stream, indent);
-               fprintf(stream, "<expression>\n");
-               ret = recursive_visit_print_expression(node, stream,
-                                       indent + 1);
-               print_tabs(stream, indent);
-               fprintf(stream, "</expression>\n");
-               return ret;
-       case NODE_OP:
-               print_tabs(stream, indent);
-               fprintf(stream, "<op type=");
-               switch (node->u.op.type) {
-               case AST_OP_UNKNOWN:
-               default:
-                       fprintf(stderr, "[error] %s: unknown op\n", __func__);
-                       return -EINVAL;
-               case AST_OP_MUL:
-                       fprintf(stream, "\"*\"");
-                       break;
-               case AST_OP_DIV:
-                       fprintf(stream, "\"/\"");
-                       break;
-               case AST_OP_MOD:
-                       fprintf(stream, "\"%%\"");
-                       break;
-               case AST_OP_PLUS:
-                       fprintf(stream, "\"+\"");
-                       break;
-               case AST_OP_MINUS:
-                       fprintf(stream, "\"-\"");
-                       break;
-               case AST_OP_BIT_RSHIFT:
-                       fprintf(stream, "\">>\"");
-                       break;
-               case AST_OP_BIT_LSHIFT:
-                       fprintf(stream, "\"<<\"");
-                       break;
-               case AST_OP_AND:
-                       fprintf(stream, "\"&&\"");
-                       break;
-               case AST_OP_OR:
-                       fprintf(stream, "\"||\"");
-                       break;
-               case AST_OP_BIT_AND:
-                       fprintf(stream, "\"&\"");
-                       break;
-               case AST_OP_BIT_OR:
-                       fprintf(stream, "\"|\"");
-                       break;
-               case AST_OP_BIT_XOR:
-                       fprintf(stream, "\"^\"");
-                       break;
-
-               case AST_OP_EQ:
-                       fprintf(stream, "\"==\"");
-                       break;
-               case AST_OP_NE:
-                       fprintf(stream, "\"!=\"");
-                       break;
-               case AST_OP_GT:
-                       fprintf(stream, "\">\"");
-                       break;
-               case AST_OP_LT:
-                       fprintf(stream, "\"<\"");
-                       break;
-               case AST_OP_GE:
-                       fprintf(stream, "\">=\"");
-                       break;
-               case AST_OP_LE:
-                       fprintf(stream, "\"<=\"");
-                       break;
-               }
-               fprintf(stream, ">\n");
-               ret = recursive_visit_print(node->u.op.lchild,
-                                       stream, indent + 1);
-               if (ret)
-                       return ret;
-               ret = recursive_visit_print(node->u.op.rchild,
-                                       stream, indent + 1);
-               if (ret)
-                       return ret;
-               print_tabs(stream, indent);
-               fprintf(stream, "</op>\n");
-               return ret;
-       case NODE_UNARY_OP:
-               print_tabs(stream, indent);
-               fprintf(stream, "<unary_op type=");
-               switch (node->u.unary_op.type) {
-               case AST_UNARY_UNKNOWN:
-               default:
-                       fprintf(stderr, "[error] %s: unknown unary_op\n", __func__);
-                       return -EINVAL;
-               case AST_UNARY_PLUS:
-                       fprintf(stream, "\"+\"");
-                       break;
-               case AST_UNARY_MINUS:
-                       fprintf(stream, "\"-\"");
-                       break;
-               case AST_UNARY_NOT:
-                       fprintf(stream, "\"!\"");
-                       break;
-               case AST_UNARY_BIT_NOT:
-                       fprintf(stream, "\"~\"");
-                       break;
-               }
-               fprintf(stream, ">\n");
-               ret = recursive_visit_print(node->u.unary_op.child,
-                                       stream, indent + 1);
-               print_tabs(stream, indent);
-               fprintf(stream, "</unary_op>\n");
-               return ret;
-       }
-       return 0;
-}
-
-LTTNG_HIDDEN
-int filter_visitor_print_xml(struct filter_parser_ctx *ctx, FILE *stream,
-                       int indent)
-{
-       return recursive_visit_print(&ctx->ast->root, stream, indent);
-}
diff --git a/src/lib/lttng-ctl/filter/memstream.h b/src/lib/lttng-ctl/filter/memstream.h
deleted file mode 100644 (file)
index cd246ee..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2012 (C) Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: MIT
- *
- */
-
-#ifndef _LTTNG_CTL_MEMSTREAM_H
-#define _LTTNG_CTL_MEMSTREAM_H
-
-#ifdef LTTNG_HAVE_FMEMOPEN
-#include <stdio.h>
-
-static inline
-FILE *lttng_fmemopen(void *buf, size_t size, const char *mode)
-{
-       return fmemopen(buf, size, mode);
-}
-
-#else /* LTTNG_HAVE_FMEMOPEN */
-
-#include <stdlib.h>
-#include <stdio.h>
-
-/*
- * Fallback for systems which don't have fmemopen. Copy buffer to a
- * temporary file, and use that file as FILE * input.
- */
-static inline
-FILE *lttng_fmemopen(void *buf, size_t size, const char *mode)
-{
-       char tmpname[PATH_MAX];
-       size_t len;
-       FILE *fp;
-       int ret;
-
-       /*
-        * Support reading only.
-        */
-       if (strcmp(mode, "rb") != 0) {
-               return NULL;
-       }
-       strncpy(tmpname, "/tmp/lttng-tmp-XXXXXX", PATH_MAX);
-       ret = mkstemp(tmpname);
-       if (ret < 0) {
-               return NULL;
-       }
-       /*
-        * We need to write to the file.
-        */
-       fp = fdopen(ret, "w+");
-       if (!fp) {
-               goto error_unlink;
-       }
-       /* Copy the entire buffer to the file */
-       len = fwrite(buf, sizeof(char), size, fp);
-       if (len != size) {
-               goto error_close;
-       }
-       ret = fseek(fp, 0L, SEEK_SET);
-       if (ret < 0) {
-               PERROR("fseek");
-               goto error_close;
-       }
-       /* We keep the handle open, but can unlink the file on the VFS. */
-       ret = unlink(tmpname);
-       if (ret < 0) {
-               PERROR("unlink");
-       }
-       return fp;
-
-error_close:
-       ret = fclose(fp);
-       if (ret < 0) {
-               PERROR("close");
-       }
-error_unlink:
-       ret = unlink(tmpname);
-       if (ret < 0) {
-               PERROR("unlink");
-       }
-       return NULL;
-}
-
-#endif /* LTTNG_HAVE_FMEMOPEN */
-
-#endif /* _LTTNG_CTL_MEMSTREAM_H */
index 81ddeb74a081c0f14c0979e9647194b9ff2e08df..4eb36a2612d952bb71d38e9cedcc4d70a47d6148 100644 (file)
 #include <lttng/userspace-probe-internal.h>
 #include <lttng/lttng-error.h>
 
 #include <lttng/userspace-probe-internal.h>
 #include <lttng/lttng-error.h>
 
-#include "filter/filter-ast.h"
-#include "filter/filter-parser.h"
-#include "filter/filter-bytecode.h"
-#include "filter/memstream.h"
+#include <common/filter/filter-ast.h>
+#include <common/filter/filter-parser.h>
+#include <common/filter/filter-bytecode.h>
+#include <common/filter/memstream.h>
 #include "lttng-ctl-helper.h"
 
 #include "lttng-ctl-helper.h"
 
-#ifdef DEBUG
-static const int print_xml = 1;
-#define dbg_printf(fmt, args...)       \
-       printf("[debug liblttng-ctl] " fmt, ## args)
-#else
-static const int print_xml = 0;
-#define dbg_printf(fmt, args...)                               \
-do {                                                           \
-       /* do nothing but check printf format */                \
-       if (0)                                                  \
-               printf("[debug liblttnctl] " fmt, ## args);     \
-} while (0)
-#endif
-
 #define COPY_DOMAIN_PACKED(dst, src)                           \
 do {                                                           \
        struct lttng_domain _tmp_domain;                        \
 #define COPY_DOMAIN_PACKED(dst, src)                           \
 do {                                                           \
        struct lttng_domain _tmp_domain;                        \
@@ -1050,133 +1036,6 @@ error:
        return NULL;
 }
 
        return NULL;
 }
 
-/*
- * Generate the filter bytecode from a given filter expression string. Put the
- * newly allocated parser context in ctxp and populate the lsm object with the
- * expression len.
- *
- * Return 0 on success else a LTTNG_ERR_* code and ctxp is untouched.
- */
-static int generate_filter(char *filter_expression,
-               struct lttcomm_session_msg *lsm, struct filter_parser_ctx **ctxp)
-{
-       int ret;
-       struct filter_parser_ctx *ctx = NULL;
-       FILE *fmem = NULL;
-
-       assert(filter_expression);
-       assert(lsm);
-       assert(ctxp);
-
-       /*
-        * Casting const to non-const, as the underlying function will use it in
-        * read-only mode.
-        */
-       fmem = lttng_fmemopen((void *) filter_expression,
-                       strlen(filter_expression), "r");
-       if (!fmem) {
-               fprintf(stderr, "Error opening memory as stream\n");
-               ret = -LTTNG_ERR_FILTER_NOMEM;
-               goto error;
-       }
-       ctx = filter_parser_ctx_alloc(fmem);
-       if (!ctx) {
-               fprintf(stderr, "Error allocating parser\n");
-               ret = -LTTNG_ERR_FILTER_NOMEM;
-               goto filter_alloc_error;
-       }
-       ret = filter_parser_ctx_append_ast(ctx);
-       if (ret) {
-               fprintf(stderr, "Parse error\n");
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-       if (print_xml) {
-               ret = filter_visitor_print_xml(ctx, stdout, 0);
-               if (ret) {
-                       fflush(stdout);
-                       fprintf(stderr, "XML print error\n");
-                       ret = -LTTNG_ERR_FILTER_INVAL;
-                       goto parse_error;
-               }
-       }
-
-       dbg_printf("Generating IR... ");
-       fflush(stdout);
-       ret = filter_visitor_ir_generate(ctx);
-       if (ret) {
-               fprintf(stderr, "Generate IR error\n");
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-       dbg_printf("done\n");
-
-       dbg_printf("Validating IR... ");
-       fflush(stdout);
-       ret = filter_visitor_ir_check_binary_op_nesting(ctx);
-       if (ret) {
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-
-       /* Normalize globbing patterns in the expression. */
-       ret = filter_visitor_ir_normalize_glob_patterns(ctx);
-       if (ret) {
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-
-       /* Validate strings used as literals in the expression. */
-       ret = filter_visitor_ir_validate_string(ctx);
-       if (ret) {
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-
-       /* Validate globbing patterns in the expression. */
-       ret = filter_visitor_ir_validate_globbing(ctx);
-       if (ret) {
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-
-       dbg_printf("done\n");
-
-       dbg_printf("Generating bytecode... ");
-       fflush(stdout);
-       ret = filter_visitor_bytecode_generate(ctx);
-       if (ret) {
-               fprintf(stderr, "Generate bytecode error\n");
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-       dbg_printf("done\n");
-       dbg_printf("Size of bytecode generated: %u bytes.\n",
-                       bytecode_get_len(&ctx->bytecode->b));
-
-       lsm->u.enable.bytecode_len = sizeof(ctx->bytecode->b)
-               + bytecode_get_len(&ctx->bytecode->b);
-       lsm->u.enable.expression_len = strlen(filter_expression) + 1;
-
-       /* No need to keep the memory stream. */
-       if (fclose(fmem) != 0) {
-               PERROR("fclose");
-       }
-
-       *ctxp = ctx;
-       return 0;
-
-parse_error:
-       filter_ir_free(ctx);
-       filter_parser_ctx_free(ctx);
-filter_alloc_error:
-       if (fclose(fmem) != 0) {
-               PERROR("fclose");
-       }
-error:
-       return ret;
-}
-
 /*
  * Enable event(s) for a channel, possibly with exclusions and a filter.
  * If no event name is specified, all events are enabled.
 /*
  * Enable event(s) for a channel, possibly with exclusions and a filter.
  * If no event name is specified, all events are enabled.
@@ -1279,10 +1138,14 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle,
                        }
                }
 
                        }
                }
 
-               ret = generate_filter(filter_expression, &lsm, &ctx);
+               ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
                if (ret) {
                        goto filter_error;
                }
                if (ret) {
                        goto filter_error;
                }
+
+               lsm.u.enable.bytecode_len = sizeof(ctx->bytecode->b)
+                       + bytecode_get_len(&ctx->bytecode->b);
+               lsm.u.enable.expression_len = strlen(filter_expression) + 1;
        }
 
        ret = lttng_dynamic_buffer_set_capacity(&payload.buffer,
        }
 
        ret = lttng_dynamic_buffer_set_capacity(&payload.buffer,
@@ -1509,10 +1372,14 @@ int lttng_disable_event_ext(struct lttng_handle *handle,
                        }
                }
 
                        }
                }
 
-               ret = generate_filter(filter_expression, &lsm, &ctx);
+               ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
                if (ret) {
                        goto filter_error;
                }
                if (ret) {
                        goto filter_error;
                }
+
+               lsm.u.enable.bytecode_len = sizeof(ctx->bytecode->b)
+                       + bytecode_get_len(&ctx->bytecode->b);
+               lsm.u.enable.expression_len = strlen(filter_expression) + 1;
        }
 
        varlen_data = zmalloc(lsm.u.disable.bytecode_len
        }
 
        varlen_data = zmalloc(lsm.u.disable.bytecode_len
This page took 0.157062 seconds and 4 git commands to generate.