/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
# 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"
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/lttng-ctl/filter/Makefile
src/lib/lttng-ctl/lttng-ctl.pc
src/bin/Makefile
src/bin/lttng-consumerd/Makefile
$(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)
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.
config \
consumer \
string-utils \
- fd-tracker
-
+ fd-tracker \
+ filter
# Common library
noinst_LTLIBRARIES = libcommon.la
EXTRA_DIST = mi-lttng-4.0.xsd
$(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
--- /dev/null
+# 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
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+#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 */
--- /dev/null
+%{
+/*
+ * 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;
+%%
--- /dev/null
+%{
+/*
+ * 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;
+ }
+ ;
--- /dev/null
+#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 */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
# SPDX-License-Identifier: GPL-2.0-only
-SUBDIRS = filter
+SUBDIRS =
AM_CPPFLAGS += -I$(srcdir) -I$(builddir)
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
+++ /dev/null
-# 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
+++ /dev/null
-#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 */
+++ /dev/null
-#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 */
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-#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 */
+++ /dev/null
-%{
-/*
- * 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;
-%%
+++ /dev/null
-%{
-/*
- * 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;
- }
- ;
+++ /dev/null
-#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 */
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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 */
#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"
-#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; \
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.
}
}
- ret = generate_filter(filter_expression, &lsm, &ctx);
+ ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
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 = generate_filter(filter_expression, &lsm, &ctx);
+ ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
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