#include <common/compat/errno.h>
#include <common/bytecode/bytecode.h>
#include <common/filter/filter-ast.h>
-#include <common/filter/filter-parser.h>
+#include <common/filter/filter-parser.hpp>
/* For error.h */
int lttng_opt_quiet = 1;
noinst_HEADERS = filter-ast.h \
filter-symbols.h
-BUILT_SOURCES = filter-parser.h
+BUILT_SOURCES = filter-parser.hpp
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-lexer.lpp \
+ filter-parser.ypp \
+ filter-visitor-xml.cpp \
+ filter-visitor-generate-ir.cpp \
+ filter-visitor-ir-check-binary-op-nesting.cpp \
+ filter-visitor-ir-validate-string.cpp \
+ filter-visitor-ir-validate-globbing.cpp \
+ filter-visitor-ir-normalize-glob-patterns.cpp \
+ filter-visitor-generate-bytecode.cpp \
filter-ast.h \
filter-ir.h \
memstream.h
-libfilter_la_CFLAGS = -include filter-symbols.h $(AM_CFLAGS)
+libfilter_la_CXXFLAGS = -include filter-symbols.h $(AM_CXXFLAGS)
libfilter_la_LIBADD = $(top_builddir)/src/common/string-utils/libstring-utils.la
AM_YFLAGS = -t -d -v -Wno-yacc
if HAVE_BISON
# we have bison: we can clean the generated parser files
-CLEANFILES += filter-parser.c filter-parser.h filter-parser.output
+CLEANFILES += filter-parser.cpp filter-parser.hpp 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
+filter-parser.cpp filter-parser.hpp: filter-parser.ypp
@echo $(ERR_MSG)
@false
-all-local: filter-parser.c filter-parser.h
+all-local: filter-parser.cpp filter-parser.hpp
endif # HAVE_BISON
if HAVE_FLEX
# we have flex: we can clean the generated lexer files
-CLEANFILES += filter-lexer.c
+CLEANFILES += filter-lexer.cpp
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
+filter-lexer.cpp: filter-lexer.lpp
@echo $(ERR_MSG)
@false
-all-local: filter-lexer.c
+all-local: filter-lexer.cpp
endif # HAVE_FLEX
AST_LINK_BRACKET,
};
+enum ast_expt_type {
+ AST_EXP_UNKNOWN = 0,
+ AST_EXP_STRING,
+ AST_EXP_CONSTANT,
+ AST_EXP_FLOAT_CONSTANT,
+ AST_EXP_IDENTIFIER,
+ AST_EXP_GLOBAL_IDENTIFIER,
+ AST_EXP_NESTED,
+};
+
struct filter_node {
/*
* Parent node is only set on demand by specific visitor.
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_expt_type type;
enum ast_link_type post_op; /* reverse */
enum ast_link_type pre_op; /* forward */
union {
+++ /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"
-#include <lttng/lttng-export.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;
-%%
-
-/*
- * The lexer symbols were (e.g. lttng_yy_create_buffer) were mistakenly
- * exported in the past, so must stay exported. Since it is difficult to tweak
- * how the lexer functions are emitted, the strategy used here was to use a
- * different prefix for the symbols (`lttng_filter_`) and define aliases with
- * the old prefix (`lttng_`).
- *
- * The `MAKE_ALIAS` macro defines one such alias.
- */
-LTTNG_EXPORT
-YY_BUFFER_STATE lttng_yy_create_buffer(FILE *file, int size, yyscan_t yyscanner);
-YY_BUFFER_STATE lttng_yy_create_buffer(FILE *file, int size, yyscan_t yyscanner)
-{
- return yy_create_buffer(file, size, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yy_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner);
-void lttng_yy_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner)
-{
- return yy_delete_buffer(b, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yy_flush_buffer (YY_BUFFER_STATE b, yyscan_t yyscanner);
-void lttng_yy_flush_buffer (YY_BUFFER_STATE b, yyscan_t yyscanner)
-{
- return yy_flush_buffer(b, yyscanner);
-}
-
-LTTNG_EXPORT
-YY_BUFFER_STATE lttng_yy_scan_buffer(char *base, yy_size_t size, yyscan_t yyscanner);
-YY_BUFFER_STATE lttng_yy_scan_buffer(char *base, yy_size_t size, yyscan_t yyscanner)
-{
- return yy_scan_buffer(base, size, yyscanner);
-}
-
-LTTNG_EXPORT
-YY_BUFFER_STATE lttng_yy_scan_bytes(const char *bytes, int len, yyscan_t yyscanner);
-YY_BUFFER_STATE lttng_yy_scan_bytes(const char *bytes, int len, yyscan_t yyscanner)
-{
- return yy_scan_bytes(bytes, len, yyscanner);
-}
-
-LTTNG_EXPORT
-YY_BUFFER_STATE lttng_yy_scan_string(const char *yy_str, yyscan_t yyscanner);
-YY_BUFFER_STATE lttng_yy_scan_string(const char *yy_str, yyscan_t yyscanner)
-{
- return yy_scan_string(yy_str, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yy_switch_to_buffer(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner);
-void lttng_yy_switch_to_buffer(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner)
-{
- return yy_switch_to_buffer(new_buffer, yyscanner);
-}
-
-LTTNG_EXPORT
-void *lttng_yyalloc(yy_size_t s, yyscan_t yyscanner);
-void *lttng_yyalloc(yy_size_t s, yyscan_t yyscanner)
-{
- return yyalloc(s, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyfree(void *p, yyscan_t yyscanner);
-void lttng_yyfree(void *p, yyscan_t yyscanner)
-{
- return yyfree(p, yyscanner);
-}
-
-LTTNG_EXPORT
-int lttng_yyget_column(yyscan_t yyscanner);
-int lttng_yyget_column(yyscan_t yyscanner)
-{
- return yyget_column(yyscanner);
-}
-
-LTTNG_EXPORT
-int lttng_yyget_debug(yyscan_t yyscanner);
-int lttng_yyget_debug(yyscan_t yyscanner)
-{
- return yyget_debug(yyscanner);
-}
-
-LTTNG_EXPORT
-YY_EXTRA_TYPE lttng_yyget_extra(yyscan_t yyscanner);
-YY_EXTRA_TYPE lttng_yyget_extra(yyscan_t yyscanner)
-{
- return yyget_extra(yyscanner);
-}
-
-LTTNG_EXPORT
-FILE *lttng_yyget_in(yyscan_t yyscanner);
-FILE *lttng_yyget_in(yyscan_t yyscanner)
-{
- return yyget_in(yyscanner);
-}
-
-LTTNG_EXPORT
-int lttng_yyget_leng(yyscan_t yyscanner);
-int lttng_yyget_leng(yyscan_t yyscanner)
-{
- return yyget_leng(yyscanner);
-}
-
-LTTNG_EXPORT
-int lttng_yyget_lineno(yyscan_t yyscanner);
-int lttng_yyget_lineno(yyscan_t yyscanner)
-{
- return yyget_lineno(yyscanner);
-}
-
-LTTNG_EXPORT
-YYSTYPE *lttng_yyget_lval(yyscan_t yyscanner);
-YYSTYPE *lttng_yyget_lval(yyscan_t yyscanner)
-{
- return yyget_lval(yyscanner);
-}
-
-LTTNG_EXPORT
-FILE *lttng_yyget_out(yyscan_t yyscanner);
-FILE *lttng_yyget_out(yyscan_t yyscanner)
-{
- return yyget_out(yyscanner);
-}
-
-LTTNG_EXPORT
-char *lttng_yyget_text(yyscan_t yyscanner);
-char *lttng_yyget_text(yyscan_t yyscanner)
-{
- return yyget_text(yyscanner);
-}
-
-LTTNG_EXPORT
-int lttng_yylex_init(yyscan_t *scanner);
-int lttng_yylex_init(yyscan_t *scanner)
-{
- return yylex_init(scanner);
-}
-
-LTTNG_EXPORT
-void lttng_yypop_buffer_state(yyscan_t yyscanner);
-void lttng_yypop_buffer_state(yyscan_t yyscanner)
-{
- return yypop_buffer_state(yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner);
-void lttng_yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner)
-{
- return yypush_buffer_state(new_buffer, yyscanner);
-}
-
-LTTNG_EXPORT
-void *lttng_yyrealloc(void *p, yy_size_t s, yyscan_t yyscanner);
-void *lttng_yyrealloc(void *p, yy_size_t s, yyscan_t yyscanner)
-{
- return yyrealloc(p, s, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_column(int _column_no, yyscan_t yyscanner);
-void lttng_yyset_column(int _column_no, yyscan_t yyscanner)
-{
- return yyset_column(_column_no, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_debug(int debug_flag, yyscan_t yyscanner);
-void lttng_yyset_debug(int debug_flag, yyscan_t yyscanner)
-{
- return yyset_debug(debug_flag, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_extra(YY_EXTRA_TYPE user_defined, yyscan_t yyscanner);
-void lttng_yyset_extra(YY_EXTRA_TYPE user_defined, yyscan_t yyscanner)
-{
- return yyset_extra(user_defined, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_in(FILE *_in_str, yyscan_t yyscanner);
-void lttng_yyset_in(FILE *_in_str, yyscan_t yyscanner)
-{
- return yyset_in(_in_str, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_lineno(int _line_number, yyscan_t yyscanner);
-void lttng_yyset_lineno(int _line_number, yyscan_t yyscanner)
-{
- return yyset_lineno(_line_number, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_lval(YYSTYPE *yylval_param, yyscan_t yyscanner);
-void lttng_yyset_lval(YYSTYPE *yylval_param, yyscan_t yyscanner)
-{
- return yyset_lval(yylval_param, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_out(FILE *_out_str, yyscan_t yyscanner);
-void lttng_yyset_out(FILE *_out_str, yyscan_t yyscanner)
-{
- return yyset_out(_out_str, yyscanner);
-}
--- /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.hpp"
+#include <lttng/lttng-export.h>
+%}
+
+%x comment_ml comment_sl string_lit char_const
+%option reentrant yylineno noyywrap bison-bridge noinput nounput
+%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;
+%%
+
+/*
+ * The lexer symbols were (e.g. lttng_yy_create_buffer) were mistakenly
+ * exported in the past, so must stay exported. Since it is difficult to tweak
+ * how the lexer functions are emitted, the strategy used here was to use a
+ * different prefix for the symbols (`lttng_filter_`) and define aliases with
+ * the old prefix (`lttng_`).
+ *
+ * The `MAKE_ALIAS` macro defines one such alias.
+ */
+LTTNG_EXPORT
+YY_BUFFER_STATE lttng_yy_create_buffer(FILE *file, int size, yyscan_t yyscanner);
+YY_BUFFER_STATE lttng_yy_create_buffer(FILE *file, int size, yyscan_t yyscanner)
+{
+ return yy_create_buffer(file, size, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yy_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner);
+void lttng_yy_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner)
+{
+ return yy_delete_buffer(b, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yy_flush_buffer (YY_BUFFER_STATE b, yyscan_t yyscanner);
+void lttng_yy_flush_buffer (YY_BUFFER_STATE b, yyscan_t yyscanner)
+{
+ return yy_flush_buffer(b, yyscanner);
+}
+
+LTTNG_EXPORT
+YY_BUFFER_STATE lttng_yy_scan_buffer(char *base, yy_size_t size, yyscan_t yyscanner);
+YY_BUFFER_STATE lttng_yy_scan_buffer(char *base, yy_size_t size, yyscan_t yyscanner)
+{
+ return yy_scan_buffer(base, size, yyscanner);
+}
+
+LTTNG_EXPORT
+YY_BUFFER_STATE lttng_yy_scan_bytes(const char *bytes, int len, yyscan_t yyscanner);
+YY_BUFFER_STATE lttng_yy_scan_bytes(const char *bytes, int len, yyscan_t yyscanner)
+{
+ return yy_scan_bytes(bytes, len, yyscanner);
+}
+
+LTTNG_EXPORT
+YY_BUFFER_STATE lttng_yy_scan_string(const char *yy_str, yyscan_t yyscanner);
+YY_BUFFER_STATE lttng_yy_scan_string(const char *yy_str, yyscan_t yyscanner)
+{
+ return yy_scan_string(yy_str, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yy_switch_to_buffer(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner);
+void lttng_yy_switch_to_buffer(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner)
+{
+ return yy_switch_to_buffer(new_buffer, yyscanner);
+}
+
+LTTNG_EXPORT
+void *lttng_yyalloc(yy_size_t s, yyscan_t yyscanner);
+void *lttng_yyalloc(yy_size_t s, yyscan_t yyscanner)
+{
+ return yyalloc(s, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyfree(void *p, yyscan_t yyscanner);
+void lttng_yyfree(void *p, yyscan_t yyscanner)
+{
+ return yyfree(p, yyscanner);
+}
+
+LTTNG_EXPORT
+int lttng_yyget_column(yyscan_t yyscanner);
+int lttng_yyget_column(yyscan_t yyscanner)
+{
+ return yyget_column(yyscanner);
+}
+
+LTTNG_EXPORT
+int lttng_yyget_debug(yyscan_t yyscanner);
+int lttng_yyget_debug(yyscan_t yyscanner)
+{
+ return yyget_debug(yyscanner);
+}
+
+LTTNG_EXPORT
+YY_EXTRA_TYPE lttng_yyget_extra(yyscan_t yyscanner);
+YY_EXTRA_TYPE lttng_yyget_extra(yyscan_t yyscanner)
+{
+ return yyget_extra(yyscanner);
+}
+
+LTTNG_EXPORT
+FILE *lttng_yyget_in(yyscan_t yyscanner);
+FILE *lttng_yyget_in(yyscan_t yyscanner)
+{
+ return yyget_in(yyscanner);
+}
+
+LTTNG_EXPORT
+int lttng_yyget_leng(yyscan_t yyscanner);
+int lttng_yyget_leng(yyscan_t yyscanner)
+{
+ return yyget_leng(yyscanner);
+}
+
+LTTNG_EXPORT
+int lttng_yyget_lineno(yyscan_t yyscanner);
+int lttng_yyget_lineno(yyscan_t yyscanner)
+{
+ return yyget_lineno(yyscanner);
+}
+
+LTTNG_EXPORT
+YYSTYPE *lttng_yyget_lval(yyscan_t yyscanner);
+YYSTYPE *lttng_yyget_lval(yyscan_t yyscanner)
+{
+ return yyget_lval(yyscanner);
+}
+
+LTTNG_EXPORT
+FILE *lttng_yyget_out(yyscan_t yyscanner);
+FILE *lttng_yyget_out(yyscan_t yyscanner)
+{
+ return yyget_out(yyscanner);
+}
+
+LTTNG_EXPORT
+char *lttng_yyget_text(yyscan_t yyscanner);
+char *lttng_yyget_text(yyscan_t yyscanner)
+{
+ return yyget_text(yyscanner);
+}
+
+LTTNG_EXPORT
+int lttng_yylex_init(yyscan_t *scanner);
+int lttng_yylex_init(yyscan_t *scanner)
+{
+ return yylex_init(scanner);
+}
+
+LTTNG_EXPORT
+void lttng_yypop_buffer_state(yyscan_t yyscanner);
+void lttng_yypop_buffer_state(yyscan_t yyscanner)
+{
+ return yypop_buffer_state(yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner);
+void lttng_yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner)
+{
+ return yypush_buffer_state(new_buffer, yyscanner);
+}
+
+LTTNG_EXPORT
+void *lttng_yyrealloc(void *p, yy_size_t s, yyscan_t yyscanner);
+void *lttng_yyrealloc(void *p, yy_size_t s, yyscan_t yyscanner)
+{
+ return yyrealloc(p, s, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_column(int _column_no, yyscan_t yyscanner);
+void lttng_yyset_column(int _column_no, yyscan_t yyscanner)
+{
+ return yyset_column(_column_no, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_debug(int debug_flag, yyscan_t yyscanner);
+void lttng_yyset_debug(int debug_flag, yyscan_t yyscanner)
+{
+ return yyset_debug(debug_flag, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_extra(YY_EXTRA_TYPE user_defined, yyscan_t yyscanner);
+void lttng_yyset_extra(YY_EXTRA_TYPE user_defined, yyscan_t yyscanner)
+{
+ return yyset_extra(user_defined, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_in(FILE *_in_str, yyscan_t yyscanner);
+void lttng_yyset_in(FILE *_in_str, yyscan_t yyscanner)
+{
+ return yyset_in(_in_str, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_lineno(int _line_number, yyscan_t yyscanner);
+void lttng_yyset_lineno(int _line_number, yyscan_t yyscanner)
+{
+ return yyset_lineno(_line_number, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_lval(YYSTYPE *yylval_param, yyscan_t yyscanner);
+void lttng_yyset_lval(YYSTYPE *yylval_param, yyscan_t yyscanner)
+{
+ return yyset_lval(yylval_param, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_out(FILE *_out_str, yyscan_t yyscanner);
+void lttng_yyset_out(FILE *_out_str, yyscan_t yyscanner)
+{
+ return yyset_out(_out_str, yyscanner);
+}
+++ /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 <inttypes.h>
-#include "common/bytecode/bytecode.h"
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "memstream.h"
-
-#include <common/compat/errno.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
-
-int yydebug;
-int filter_parser_debug = 0;
-
-int yyparse(struct filter_parser_ctx *parser_ctx, yyscan_t scanner);
-int yylex(union YYSTYPE *yyval, yyscan_t scanner);
-int yylex_init_extra(struct filter_parser_ctx *parser_ctx, yyscan_t * ptr_yy_globals);
-int yylex_destroy(yyscan_t yyparser_ctx);
-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",
-};
-
-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;
-}
-
-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);
-}
-
-int filter_parser_ctx_append_ast(struct filter_parser_ctx *parser_ctx)
-{
- return yyparse(parser_ctx, parser_ctx->scanner);
-}
-
-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;
-}
-
-void filter_parser_ctx_free(struct filter_parser_ctx *parser_ctx)
-{
- int ret;
-
- ret = yylex_destroy(parser_ctx->scanner);
- if (ret)
- fprintf(stderr, "yylex_destroy error\n");
-
- filter_ast_free(parser_ctx->ast);
- free_strings(&parser_ctx->allocated_strings);
- filter_ir_free(parser_ctx);
- free(parser_ctx->bytecode);
- free(parser_ctx->bytecode_reloc);
-
- free(parser_ctx);
-}
-
-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;
-
- LTTNG_ASSERT(filter_expression);
- LTTNG_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"
-
-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
+%{
+/*
+ * 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 <inttypes.h>
+#include "common/bytecode/bytecode.h"
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#include "memstream.h"
+
+#include <common/compat/errno.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
+
+int filter_parser_debug = 0;
+
+int yyparse(struct filter_parser_ctx *parser_ctx, yyscan_t scanner);
+int yylex(union YYSTYPE *yyval, yyscan_t scanner);
+int yylex_init_extra(struct filter_parser_ctx *parser_ctx, yyscan_t * ptr_yy_globals);
+int yylex_destroy(yyscan_t yyparser_ctx);
+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_str(enum node_type type)
+{
+ switch (type) {
+ case NODE_UNKNOWN:
+ return "NODE_UNKNOWN";
+ case NODE_ROOT:
+ return "NODE_ROOT";
+ case NODE_EXPRESSION:
+ return "NODE_EXPRESSION";
+ case NODE_OP:
+ return "NODE_OP";
+ case NODE_UNARY_OP:
+ return "NODE_UNARY_OP";
+ case NR_NODE_TYPES:
+ abort();
+ }
+
+ abort();
+};
+
+const char *node_type(struct filter_node *node)
+{
+ if (node->type < NR_NODE_TYPES)
+ return node_type_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 = (gc_string *) 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;
+}
+
+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 = (filter_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 = (filter_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 = (filter_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);
+}
+
+int filter_parser_ctx_append_ast(struct filter_parser_ctx *parser_ctx)
+{
+ return yyparse(parser_ctx, parser_ctx->scanner);
+}
+
+struct filter_parser_ctx *filter_parser_ctx_alloc(FILE *input)
+{
+ struct filter_parser_ctx *parser_ctx;
+ int ret;
+
+ yydebug = filter_parser_debug;
+
+ parser_ctx = (filter_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;
+}
+
+void filter_parser_ctx_free(struct filter_parser_ctx *parser_ctx)
+{
+ int ret;
+
+ ret = yylex_destroy(parser_ctx->scanner);
+ if (ret)
+ fprintf(stderr, "yylex_destroy error\n");
+
+ filter_ast_free(parser_ctx->ast);
+ free_strings(&parser_ctx->allocated_strings);
+ filter_ir_free(parser_ctx);
+ free(parser_ctx->bytecode);
+ free(parser_ctx->bytecode_reloc);
+
+ free(parser_ctx);
+}
+
+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;
+
+ LTTNG_ASSERT(filter_expression);
+ LTTNG_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"
+
+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
-/*
- * 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 <common/align.h>
-#include <common/compat/errno.h>
-#include <common/compat/string.h>
-
-#include "common/align.h"
-#include "common/bytecode/bytecode.h"
-#include "common/compat/string.h"
-#include "common/macros.h"
-#include "filter-ast.h"
-#include "filter-ir.h"
-
-#ifndef max_t
-#define max_t(type, a, b) ((type) ((a) > (b) ? (a) : (b)))
-#endif
-
-static
-int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
- struct ir_op *node);
-
-static
-int bytecode_patch(struct lttng_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 = BYTECODE_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 bytecode_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 = BYTECODE_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 = BYTECODE_OP_GET_CONTEXT_REF;
- if (append_str(symbol, "$app.")) {
- return -ENOMEM;
- }
- need_dot = false;
- break;
- case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
- *op_type = BYTECODE_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 bytecode_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:
- {
- ret = bytecode_push_get_context_root(&ctx->bytecode);
-
- if (ret) {
- return ret;
- }
-
- break;
- }
- case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
- {
- ret = bytecode_push_get_app_context_root(
- &ctx->bytecode);
-
- if (ret) {
- return ret;
- }
-
- break;
- }
- case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
- {
- ret = bytecode_push_get_payload_root(&ctx->bytecode);
-
- if (ret) {
- return ret;
- }
-
- break;
- }
- case IR_LOAD_EXPRESSION_GET_SYMBOL:
- {
- ret = bytecode_push_get_symbol(&ctx->bytecode,
- &ctx->bytecode_reloc, op->u.symbol);
-
- if (ret) {
- return ret;
- }
-
- break;
- }
- case IR_LOAD_EXPRESSION_GET_INDEX:
- {
- ret = bytecode_push_get_index_u64(
- &ctx->bytecode, op->u.index);
-
- if (ret) {
- return ret;
- }
-
- break;
- }
- case IR_LOAD_EXPRESSION_LOAD_FIELD:
- {
- struct load_op *insn;
- uint32_t insn_len = sizeof(struct load_op);
-
- insn = calloc(insn_len, 1);
- if (!insn)
- return -ENOMEM;
- insn->op = BYTECODE_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 = BYTECODE_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 = BYTECODE_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 = BYTECODE_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 = BYTECODE_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 = BYTECODE_OP_UNARY_MINUS;
- return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
- case AST_UNARY_NOT:
- insn.op = BYTECODE_OP_UNARY_NOT;
- return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
- case AST_UNARY_BIT_NOT:
- insn.op = BYTECODE_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 = BYTECODE_OP_MUL;
- break;
- case AST_OP_DIV:
- insn.op = BYTECODE_OP_DIV;
- break;
- case AST_OP_MOD:
- insn.op = BYTECODE_OP_MOD;
- break;
- case AST_OP_PLUS:
- insn.op = BYTECODE_OP_PLUS;
- break;
- case AST_OP_MINUS:
- insn.op = BYTECODE_OP_MINUS;
- break;
- case AST_OP_BIT_RSHIFT:
- insn.op = BYTECODE_OP_BIT_RSHIFT;
- break;
- case AST_OP_BIT_LSHIFT:
- insn.op = BYTECODE_OP_BIT_LSHIFT;
- break;
- case AST_OP_BIT_AND:
- insn.op = BYTECODE_OP_BIT_AND;
- break;
- case AST_OP_BIT_OR:
- insn.op = BYTECODE_OP_BIT_OR;
- break;
- case AST_OP_BIT_XOR:
- insn.op = BYTECODE_OP_BIT_XOR;
- break;
-
- case AST_OP_EQ:
- insn.op = BYTECODE_OP_EQ;
- break;
- case AST_OP_NE:
- insn.op = BYTECODE_OP_NE;
- break;
- case AST_OP_GT:
- insn.op = BYTECODE_OP_GT;
- break;
- case AST_OP_LT:
- insn.op = BYTECODE_OP_LT;
- break;
- case AST_OP_GE:
- insn.op = BYTECODE_OP_GE;
- break;
- case AST_OP_LE:
- insn.op = BYTECODE_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 = BYTECODE_OP_CAST_TO_S64;
- } else {
- cast_insn.op = BYTECODE_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 = BYTECODE_OP_AND;
- break;
- case AST_OP_OR:
- insn.op = BYTECODE_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 = BYTECODE_OP_CAST_TO_S64;
- } else {
- cast_insn.op = BYTECODE_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);
- }
-}
-
-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;
- }
-}
-
-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-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 <common/align.h>
+#include <common/compat/errno.h>
+#include <common/compat/string.h>
+
+#include "common/align.h"
+#include "common/bytecode/bytecode.h"
+#include "common/compat/string.h"
+#include "common/macros.h"
+#include "filter-ast.h"
+#include "filter-ir.h"
+
+#ifndef max_t
+#define max_t(type, a, b) ((type) ((a) > (b) ? (a) : (b)))
+#endif
+
+static
+int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
+ struct ir_op *node);
+
+static
+int bytecode_patch(struct lttng_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 = BYTECODE_OP_RETURN;
+ return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+}
+
+static
+int append_str(char **s, const char *append)
+{
+ char *old_str = *s;
+ char *new_str;
+ size_t oldlen = (old_str == NULL) ? 0 : strlen(old_str);
+ size_t appendlen = strlen(append);
+
+ new_str = (char *) calloc(oldlen + appendlen + 1, 1);
+ if (!new_str) {
+ return -ENOMEM;
+ }
+ if (oldlen) {
+ strcpy(new_str, old_str);
+ }
+ strcat(new_str, append);
+ *s = new_str;
+ free(old_str);
+ return 0;
+}
+
+/*
+ * 1: match
+ * 0: no match
+ * < 0: error
+ */
+static
+int load_expression_legacy_match(const struct ir_load_expression *exp,
+ enum bytecode_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 = BYTECODE_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 = BYTECODE_OP_GET_CONTEXT_REF;
+ if (append_str(symbol, "$app.")) {
+ return -ENOMEM;
+ }
+ need_dot = false;
+ break;
+ case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
+ *op_type = BYTECODE_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 bytecode_op op_type;
+ char *symbol = NULL;
+ int ret;
+
+ ret = load_expression_legacy_match(exp, &op_type, &symbol);
+ if (ret <= 0) {
+ goto end;
+ }
+ insn = (load_op *) 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:
+ {
+ ret = bytecode_push_get_context_root(&ctx->bytecode);
+
+ if (ret) {
+ return ret;
+ }
+
+ break;
+ }
+ case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
+ {
+ ret = bytecode_push_get_app_context_root(
+ &ctx->bytecode);
+
+ if (ret) {
+ return ret;
+ }
+
+ break;
+ }
+ case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
+ {
+ ret = bytecode_push_get_payload_root(&ctx->bytecode);
+
+ if (ret) {
+ return ret;
+ }
+
+ break;
+ }
+ case IR_LOAD_EXPRESSION_GET_SYMBOL:
+ {
+ ret = bytecode_push_get_symbol(&ctx->bytecode,
+ &ctx->bytecode_reloc, op->u.symbol);
+
+ if (ret) {
+ return ret;
+ }
+
+ break;
+ }
+ case IR_LOAD_EXPRESSION_GET_INDEX:
+ {
+ ret = bytecode_push_get_index_u64(
+ &ctx->bytecode, op->u.index);
+
+ if (ret) {
+ return ret;
+ }
+
+ break;
+ }
+ case IR_LOAD_EXPRESSION_LOAD_FIELD:
+ {
+ struct load_op *insn;
+ uint32_t insn_len = sizeof(struct load_op);
+
+ insn = (load_op *) calloc(insn_len, 1);
+ if (!insn)
+ return -ENOMEM;
+ insn->op = BYTECODE_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 = (load_op *) 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 = BYTECODE_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 = BYTECODE_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 = (load_op *) calloc(insn_len, 1);
+ if (!insn)
+ return -ENOMEM;
+ insn->op = BYTECODE_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 = (load_op *) calloc(insn_len, 1);
+ if (!insn)
+ return -ENOMEM;
+ insn->op = BYTECODE_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 = BYTECODE_OP_UNARY_MINUS;
+ return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+ case AST_UNARY_NOT:
+ insn.op = BYTECODE_OP_UNARY_NOT;
+ return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+ case AST_UNARY_BIT_NOT:
+ insn.op = BYTECODE_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 = BYTECODE_OP_MUL;
+ break;
+ case AST_OP_DIV:
+ insn.op = BYTECODE_OP_DIV;
+ break;
+ case AST_OP_MOD:
+ insn.op = BYTECODE_OP_MOD;
+ break;
+ case AST_OP_PLUS:
+ insn.op = BYTECODE_OP_PLUS;
+ break;
+ case AST_OP_MINUS:
+ insn.op = BYTECODE_OP_MINUS;
+ break;
+ case AST_OP_BIT_RSHIFT:
+ insn.op = BYTECODE_OP_BIT_RSHIFT;
+ break;
+ case AST_OP_BIT_LSHIFT:
+ insn.op = BYTECODE_OP_BIT_LSHIFT;
+ break;
+ case AST_OP_BIT_AND:
+ insn.op = BYTECODE_OP_BIT_AND;
+ break;
+ case AST_OP_BIT_OR:
+ insn.op = BYTECODE_OP_BIT_OR;
+ break;
+ case AST_OP_BIT_XOR:
+ insn.op = BYTECODE_OP_BIT_XOR;
+ break;
+
+ case AST_OP_EQ:
+ insn.op = BYTECODE_OP_EQ;
+ break;
+ case AST_OP_NE:
+ insn.op = BYTECODE_OP_NE;
+ break;
+ case AST_OP_GT:
+ insn.op = BYTECODE_OP_GT;
+ break;
+ case AST_OP_LT:
+ insn.op = BYTECODE_OP_LT;
+ break;
+ case AST_OP_GE:
+ insn.op = BYTECODE_OP_GE;
+ break;
+ case AST_OP_LE:
+ insn.op = BYTECODE_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 = BYTECODE_OP_CAST_TO_S64;
+ } else {
+ cast_insn.op = BYTECODE_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 = BYTECODE_OP_AND;
+ break;
+ case AST_OP_OR:
+ insn.op = BYTECODE_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 = BYTECODE_OP_CAST_TO_S64;
+ } else {
+ cast_insn.op = BYTECODE_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);
+ }
+}
+
+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;
+ }
+}
+
+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 <inttypes.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-#include <common/compat/errno.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)
-{
- LTTNG_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 (;;) {
- LTTNG_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;
- if (bracket_node->type != NODE_EXPRESSION ||
- bracket_node->u.expression.type != AST_EXP_CONSTANT) {
- fprintf(stderr, "[error] Expecting constant index in array expression\n");
- goto error;
- }
- 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;
-}
-
-void filter_ir_free(struct filter_parser_ctx *ctx)
-{
- filter_free_ir_recursive(ctx->ir_root);
- ctx->ir_root = NULL;
-}
-
-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-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 <inttypes.h>
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#include "filter-ir.h"
+
+#include <common/compat/errno.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 = (ir_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)
+{
+ LTTNG_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 = (ir_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 = (ir_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 = (ir_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 (;;) {
+ LTTNG_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 = (ir_load_expression *) calloc(sizeof(struct ir_load_expression), 1);
+ if (!load_exp)
+ return NULL;
+
+ /* Root */
+ load_exp_op = (ir_load_expression_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 = (ir_load_expression_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;
+ if (bracket_node->type != NODE_EXPRESSION ||
+ bracket_node->u.expression.type != AST_EXP_CONSTANT) {
+ fprintf(stderr, "[error] Expecting constant index in array expression\n");
+ goto error;
+ }
+ load_exp_op = (ir_load_expression_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 = (ir_load_expression_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 = (ir_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 = (ir_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 = (ir_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 = (ir_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 = (ir_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;
+}
+
+void filter_ir_free(struct filter_parser_ctx *ctx)
+{
+ filter_free_ir_recursive(ctx->ir_root);
+ ctx->ir_root = NULL;
+}
+
+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 <inttypes.h>
-
-#include <common/compat/errno.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-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 <inttypes.h>
+
+#include <common/compat/errno.h>
+
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#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 <inttypes.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-#include <common/compat/errno.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);
- }
- }
-}
-
-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-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 <inttypes.h>
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#include "filter-ir.h"
+
+#include <common/compat/errno.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);
+ }
+ }
+}
+
+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 <inttypes.h>
-
-#include <common/compat/errno.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) {
- LTTNG_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.
- */
-int filter_visitor_ir_normalize_glob_patterns(struct filter_parser_ctx *ctx)
-{
- return normalize_glob_patterns(ctx->ir_root);
-}
--- /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 <inttypes.h>
+
+#include <common/compat/errno.h>
+#include <common/macros.h>
+#include <common/string-utils/string-utils.h>
+
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#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) {
+ LTTNG_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.
+ */
+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 <inttypes.h>
-
-#include <common/compat/errno.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 !=.
- */
-int filter_visitor_ir_validate_globbing(struct filter_parser_ctx *ctx)
-{
- return validate_globbing(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 <inttypes.h>
+
+#include <common/compat/errno.h>
+#include <common/macros.h>
+
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#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 !=.
+ */
+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 <inttypes.h>
-
-#include <common/macros.h>
-#include <common/compat/errno.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;
-
- LTTNG_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);
- }
- }
-}
-
-int filter_visitor_ir_validate_string(struct filter_parser_ctx *ctx)
-{
- return validate_string(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 <inttypes.h>
+
+#include <common/macros.h>
+#include <common/compat/errno.h>
+
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#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;
+
+ LTTNG_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);
+ }
+ }
+}
+
+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 <inttypes.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-
-#include <common/compat/errno.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;
-}
-
-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
+/*
+ * 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 <inttypes.h>
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+
+#include <common/compat/errno.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;
+}
+
+int filter_visitor_print_xml(struct filter_parser_ctx *ctx, FILE *stream,
+ int indent)
+{
+ return recursive_visit_print(&ctx->ast->root, stream, indent);
+}
#include "lttng-ctl-helper.h"
#include <common/filter/filter-ast.h>
-#include <common/filter/filter-parser.h>
+#include <common/filter/filter-parser.hpp>
#include <common/filter/memstream.h>
#define COPY_DOMAIN_PACKED(dst, src) \