From: Simon Marchi Date: Wed, 6 Oct 2021 16:16:33 +0000 (-0400) Subject: common: compile libfilter as C++ X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=commitdiff_plain;h=348ddc5c9107149d48b1f12d31a7e75e9b73b4da common: compile libfilter as C++ This patch renames filter-lexer.l to filter-lexer.lpp and filter-parser.y to filter-parser.ypp. That makes automake pass the right options to flex/bison to generate C++ code. In filter-lexer.lpp, Instead of having declarations with the `unused` attribute for yyunput and yyinput, use the noinput and nounput options. The rest of the changes are standard C to C++ conversion stuff. Change-Id: Ie4bf1981b970145f97e8db1d88edaa2d9b95aef4 Signed-off-by: Simon Marchi Signed-off-by: Jérémie Galarneau --- diff --git a/src/common/filter-grammar-test.cpp b/src/common/filter-grammar-test.cpp index bd8f2de7f..75eb2c6ca 100644 --- a/src/common/filter-grammar-test.cpp +++ b/src/common/filter-grammar-test.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include /* For error.h */ int lttng_opt_quiet = 1; diff --git a/src/common/filter/Makefile.am b/src/common/filter/Makefile.am index 629280356..4a6e4ff8d 100644 --- a/src/common/filter/Makefile.am +++ b/src/common/filter/Makefile.am @@ -6,21 +6,22 @@ noinst_LTLIBRARIES = libfilter.la 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 @@ -30,32 +31,32 @@ CLEANFILES = 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 diff --git a/src/common/filter/filter-ast.h b/src/common/filter/filter-ast.h index d7a567445..5033b46ea 100644 --- a/src/common/filter/filter-ast.h +++ b/src/common/filter/filter-ast.h @@ -93,6 +93,16 @@ enum ast_link_type { 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. @@ -110,15 +120,7 @@ struct filter_node { 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 { diff --git a/src/common/filter/filter-lexer.l b/src/common/filter/filter-lexer.l deleted file mode 100644 index 9da4645e5..000000000 --- a/src/common/filter/filter-lexer.l +++ /dev/null @@ -1,342 +0,0 @@ -%{ -/* - * filter-lexer.l - * - * LTTng filter lexer - * - * Copyright 2012 Mathieu Desnoyers - * - * SPDX-License-Identifier: LGPL-2.1-only - * - */ - -#include -#include "filter-ast.h" -#include "filter-parser.h" -#include - -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); -[^*\n]* /* eat anything that's not a '*' */ -"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ -\n ++yylineno; -"*"+"/" BEGIN(INITIAL); - -"//" BEGIN(comment_sl); -[^\n]*\n ++yylineno; BEGIN(INITIAL); - -L\' BEGIN(char_const); return CHARACTER_CONSTANT_START; -\' BEGIN(char_const); return CHARACTER_CONSTANT_START; -\' BEGIN(INITIAL); return SQUOTE; - -L\" BEGIN(string_lit); return STRING_LITERAL_START; -\" BEGIN(string_lit); return STRING_LITERAL_START; -\" BEGIN(INITIAL); return DQUOTE; - -ESCSEQ return ESCSEQ; -\n ; /* ignore */ -. 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("\n", yytext); setstring(yyextra, yylval, yytext); return GLOBAL_IDENTIFIER; -{IDENTIFIER} printf_debug("\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); -} diff --git a/src/common/filter/filter-lexer.lpp b/src/common/filter/filter-lexer.lpp new file mode 100644 index 000000000..acd4c0be8 --- /dev/null +++ b/src/common/filter/filter-lexer.lpp @@ -0,0 +1,337 @@ +%{ +/* + * filter-lexer.l + * + * LTTng filter lexer + * + * Copyright 2012 Mathieu Desnoyers + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include "filter-ast.h" +#include "filter-parser.hpp" +#include +%} + +%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); +[^*\n]* /* eat anything that's not a '*' */ +"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ +\n ++yylineno; +"*"+"/" BEGIN(INITIAL); + +"//" BEGIN(comment_sl); +[^\n]*\n ++yylineno; BEGIN(INITIAL); + +L\' BEGIN(char_const); return CHARACTER_CONSTANT_START; +\' BEGIN(char_const); return CHARACTER_CONSTANT_START; +\' BEGIN(INITIAL); return SQUOTE; + +L\" BEGIN(string_lit); return STRING_LITERAL_START; +\" BEGIN(string_lit); return STRING_LITERAL_START; +\" BEGIN(INITIAL); return DQUOTE; + +ESCSEQ return ESCSEQ; +\n ; /* ignore */ +. 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("\n", yytext); setstring(yyextra, yylval, yytext); return GLOBAL_IDENTIFIER; +{IDENTIFIER} printf_debug("\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); +} diff --git a/src/common/filter/filter-parser.y b/src/common/filter/filter-parser.y deleted file mode 100644 index b43561fb3..000000000 --- a/src/common/filter/filter-parser.y +++ /dev/null @@ -1,802 +0,0 @@ -%{ -/* - * filter-parser.y - * - * LTTng filter expression parser - * - * Copyright 2012 Mathieu Desnoyers - * - * SPDX-License-Identifier: LGPL-2.1-only - * - * Grammar inspired from http://www.quut.com/c/ANSI-C-grammar-y.html - */ - -#include -#include -#include -#include -#include -#include "common/bytecode/bytecode.h" -#include "filter-ast.h" -#include "filter-parser.h" -#include "memstream.h" - -#include -#include - -#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 IDENTIFIER GLOBAL_IDENTIFIER -%token ERROR -%union -{ - long long ll; - char c; - struct gc_string *gs; - struct filter_node *n; -} - -%type s_char s_char_sequence c_char c_char_sequence - -%type primary_expression -%type prefix_expression -%type prefix_expression_rec -%type postfix_expression -%type unary_expression -%type unary_operator -%type multiplicative_expression -%type additive_expression -%type shift_expression -%type relational_expression -%type equality_expression -%type and_expression -%type exclusive_or_expression -%type inclusive_or_expression -%type logical_and_expression -%type logical_or_expression -%type expression -%type identifiers - -%% - - -/* 1.5 Constants */ - -c_char_sequence: - c_char - { $$ = $1; } - | c_char_sequence c_char - { $$ = gc_string_append(parser_ctx, $1, $2); } - ; - -c_char: - CHAR_STRING_TOKEN - { $$ = yylval.gs; } - | ESCSEQ - { - parse_error(parser_ctx, "escape sequences not supported yet"); - } - ; - -/* 1.6 String literals */ - -s_char_sequence: - s_char - { $$ = $1; } - | s_char_sequence s_char - { $$ = gc_string_append(parser_ctx, $1, $2); } - ; - -s_char: - CHAR_STRING_TOKEN - { $$ = yylval.gs; } - | ESCSEQ - { - parse_error(parser_ctx, "escape sequences not supported yet"); - } - ; - -primary_expression: - DECIMAL_CONSTANT - { - $$ = make_node(parser_ctx, NODE_EXPRESSION); - $$->u.expression.type = AST_EXP_CONSTANT; - if (sscanf(yylval.gs->s, "%" WIDTH_u64_SCANF_IS_A_BROKEN_API SCNu64, - &$$->u.expression.u.constant) != 1) { - parse_error(parser_ctx, "cannot scanf decimal constant"); - } - } - | OCTAL_CONSTANT - { - $$ = make_node(parser_ctx, NODE_EXPRESSION); - $$->u.expression.type = AST_EXP_CONSTANT; - if (!strcmp(yylval.gs->s, "0")) { - $$->u.expression.u.constant = 0; - } else if (sscanf(yylval.gs->s, "0%" WIDTH_o64_SCANF_IS_A_BROKEN_API SCNo64, - &$$->u.expression.u.constant) != 1) { - parse_error(parser_ctx, "cannot scanf octal constant"); - } - } - | HEXADECIMAL_CONSTANT - { - $$ = make_node(parser_ctx, NODE_EXPRESSION); - $$->u.expression.type = AST_EXP_CONSTANT; - if (sscanf(yylval.gs->s, "0x%" WIDTH_x64_SCANF_IS_A_BROKEN_API SCNx64, - &$$->u.expression.u.constant) != 1) { - parse_error(parser_ctx, "cannot scanf hexadecimal constant"); - } - } - | FLOAT_CONSTANT - { - $$ = make_node(parser_ctx, NODE_EXPRESSION); - $$->u.expression.type = AST_EXP_FLOAT_CONSTANT; - if (sscanf(yylval.gs->s, "%" WIDTH_lg_SCANF_IS_A_BROKEN_API "lg", - &$$->u.expression.u.float_constant) != 1) { - parse_error(parser_ctx, "cannot scanf float constant"); - } - } - | STRING_LITERAL_START DQUOTE - { - $$ = make_node(parser_ctx, NODE_EXPRESSION); - $$->u.expression.type = AST_EXP_STRING; - $$->u.expression.u.string = ""; - } - | STRING_LITERAL_START s_char_sequence DQUOTE - { - $$ = make_node(parser_ctx, NODE_EXPRESSION); - $$->u.expression.type = AST_EXP_STRING; - $$->u.expression.u.string = $2->s; - } - | CHARACTER_CONSTANT_START c_char_sequence SQUOTE - { - $$ = make_node(parser_ctx, NODE_EXPRESSION); - $$->u.expression.type = AST_EXP_STRING; - $$->u.expression.u.string = $2->s; - } - | LPAREN expression RPAREN - { - $$ = make_node(parser_ctx, NODE_EXPRESSION); - $$->u.expression.type = AST_EXP_NESTED; - $$->u.expression.u.child = $2; - } - ; - -identifiers - : IDENTIFIER - { - $$ = make_node(parser_ctx, NODE_EXPRESSION); - $$->u.expression.type = AST_EXP_IDENTIFIER; - $$->u.expression.u.identifier = yylval.gs->s; - } - | GLOBAL_IDENTIFIER - { - $$ = make_node(parser_ctx, NODE_EXPRESSION); - $$->u.expression.type = AST_EXP_GLOBAL_IDENTIFIER; - $$->u.expression.u.identifier = yylval.gs->s; - } - ; - -prefix_expression_rec - : LSBRAC unary_expression RSBRAC - { - $$ = $2; - } - | LSBRAC unary_expression RSBRAC prefix_expression_rec - { - $$ = $2; - $$->u.expression.pre_op = AST_LINK_BRACKET; - $$->u.expression.prev = $4; - } - ; - -prefix_expression - : identifiers - { - $$ = $1; - } - | identifiers prefix_expression_rec - { - $$ = $1; - $$->u.expression.pre_op = AST_LINK_BRACKET; - $$->u.expression.next_bracket = $2; - } - ; - -postfix_expression - : prefix_expression - { - $$ = $1; - } - | postfix_expression DOT prefix_expression - { - $$ = $3; - $$->u.expression.post_op = AST_LINK_DOT; - $$->u.expression.prev = $1; - } - | postfix_expression RARROW prefix_expression - { - $$ = $3; - $$->u.expression.post_op = AST_LINK_RARROW; - $$->u.expression.prev = $1; - } - ; - -unary_expression - : postfix_expression - { $$ = $1; } - | primary_expression - { $$ = $1; } - | unary_operator unary_expression - { - $$ = $1; - $$->u.unary_op.child = $2; - } - ; - -unary_operator - : PLUS - { - $$ = make_node(parser_ctx, NODE_UNARY_OP); - $$->u.unary_op.type = AST_UNARY_PLUS; - } - | MINUS - { - $$ = make_node(parser_ctx, NODE_UNARY_OP); - $$->u.unary_op.type = AST_UNARY_MINUS; - } - | NOT_OP - { - $$ = make_node(parser_ctx, NODE_UNARY_OP); - $$->u.unary_op.type = AST_UNARY_NOT; - } - | NOT_BIN - { - $$ = make_node(parser_ctx, NODE_UNARY_OP); - $$->u.unary_op.type = AST_UNARY_BIT_NOT; - } - ; - -multiplicative_expression - : unary_expression - { $$ = $1; } - | multiplicative_expression STAR unary_expression - { - $$ = make_op_node(parser_ctx, AST_OP_MUL, $1, $3); - } - | multiplicative_expression DIV_OP unary_expression - { - $$ = make_op_node(parser_ctx, AST_OP_DIV, $1, $3); - } - | multiplicative_expression MOD_OP unary_expression - { - $$ = make_op_node(parser_ctx, AST_OP_MOD, $1, $3); - } - ; - -additive_expression - : multiplicative_expression - { $$ = $1; } - | additive_expression PLUS multiplicative_expression - { - $$ = make_op_node(parser_ctx, AST_OP_PLUS, $1, $3); - } - | additive_expression MINUS multiplicative_expression - { - $$ = make_op_node(parser_ctx, AST_OP_MINUS, $1, $3); - } - ; - -shift_expression - : additive_expression - { $$ = $1; } - | shift_expression LEFT_OP additive_expression - { - $$ = make_op_node(parser_ctx, AST_OP_BIT_LSHIFT, $1, $3); - } - | shift_expression RIGHT_OP additive_expression - { - $$ = make_op_node(parser_ctx, AST_OP_BIT_RSHIFT, $1, $3); - } - ; - -and_expression - : shift_expression - { $$ = $1; } - | and_expression AND_BIN shift_expression - { - $$ = make_op_node(parser_ctx, AST_OP_BIT_AND, $1, $3); - } - ; - -exclusive_or_expression - : and_expression - { $$ = $1; } - | exclusive_or_expression XOR_BIN and_expression - { - $$ = make_op_node(parser_ctx, AST_OP_BIT_XOR, $1, $3); - } - ; - -inclusive_or_expression - : exclusive_or_expression - { $$ = $1; } - | inclusive_or_expression OR_BIN exclusive_or_expression - { - $$ = make_op_node(parser_ctx, AST_OP_BIT_OR, $1, $3); - } - ; - -relational_expression - : inclusive_or_expression - { $$ = $1; } - | relational_expression LT_OP inclusive_or_expression - { - $$ = make_op_node(parser_ctx, AST_OP_LT, $1, $3); - } - | relational_expression GT_OP inclusive_or_expression - { - $$ = make_op_node(parser_ctx, AST_OP_GT, $1, $3); - } - | relational_expression LE_OP inclusive_or_expression - { - $$ = make_op_node(parser_ctx, AST_OP_LE, $1, $3); - } - | relational_expression GE_OP inclusive_or_expression - { - $$ = make_op_node(parser_ctx, AST_OP_GE, $1, $3); - } - ; - -equality_expression - : relational_expression - { $$ = $1; } - | equality_expression EQ_OP relational_expression - { - $$ = make_op_node(parser_ctx, AST_OP_EQ, $1, $3); - } - | equality_expression NE_OP relational_expression - { - $$ = make_op_node(parser_ctx, AST_OP_NE, $1, $3); - } - ; - -logical_and_expression - : equality_expression - { $$ = $1; } - | logical_and_expression AND_OP equality_expression - { - $$ = make_op_node(parser_ctx, AST_OP_AND, $1, $3); - } - ; - -logical_or_expression - : logical_and_expression - { $$ = $1; } - | logical_or_expression OR_OP logical_and_expression - { - $$ = make_op_node(parser_ctx, AST_OP_OR, $1, $3); - } - ; - -expression - : logical_or_expression - { $$ = $1; } - ; - -translation_unit - : expression - { - parser_ctx->ast->root.u.root.child = $1; - } - ; diff --git a/src/common/filter/filter-parser.ypp b/src/common/filter/filter-parser.ypp new file mode 100644 index 000000000..d654ecc84 --- /dev/null +++ b/src/common/filter/filter-parser.ypp @@ -0,0 +1,814 @@ +%{ +/* + * filter-parser.y + * + * LTTng filter expression parser + * + * Copyright 2012 Mathieu Desnoyers + * + * SPDX-License-Identifier: LGPL-2.1-only + * + * Grammar inspired from http://www.quut.com/c/ANSI-C-grammar-y.html + */ + +#include +#include +#include +#include +#include +#include "common/bytecode/bytecode.h" +#include "filter-ast.h" +#include "filter-parser.hpp" +#include "memstream.h" + +#include +#include + +#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 IDENTIFIER GLOBAL_IDENTIFIER +%token ERROR +%union +{ + long long ll; + char c; + struct gc_string *gs; + struct filter_node *n; +} + +%type s_char s_char_sequence c_char c_char_sequence + +%type primary_expression +%type prefix_expression +%type prefix_expression_rec +%type postfix_expression +%type unary_expression +%type unary_operator +%type multiplicative_expression +%type additive_expression +%type shift_expression +%type relational_expression +%type equality_expression +%type and_expression +%type exclusive_or_expression +%type inclusive_or_expression +%type logical_and_expression +%type logical_or_expression +%type expression +%type identifiers + +%% + + +/* 1.5 Constants */ + +c_char_sequence: + c_char + { $$ = $1; } + | c_char_sequence c_char + { $$ = gc_string_append(parser_ctx, $1, $2); } + ; + +c_char: + CHAR_STRING_TOKEN + { $$ = yylval.gs; } + | ESCSEQ + { + parse_error(parser_ctx, "escape sequences not supported yet"); + } + ; + +/* 1.6 String literals */ + +s_char_sequence: + s_char + { $$ = $1; } + | s_char_sequence s_char + { $$ = gc_string_append(parser_ctx, $1, $2); } + ; + +s_char: + CHAR_STRING_TOKEN + { $$ = yylval.gs; } + | ESCSEQ + { + parse_error(parser_ctx, "escape sequences not supported yet"); + } + ; + +primary_expression: + DECIMAL_CONSTANT + { + $$ = make_node(parser_ctx, NODE_EXPRESSION); + $$->u.expression.type = AST_EXP_CONSTANT; + if (sscanf(yylval.gs->s, "%" WIDTH_u64_SCANF_IS_A_BROKEN_API SCNu64, + &$$->u.expression.u.constant) != 1) { + parse_error(parser_ctx, "cannot scanf decimal constant"); + } + } + | OCTAL_CONSTANT + { + $$ = make_node(parser_ctx, NODE_EXPRESSION); + $$->u.expression.type = AST_EXP_CONSTANT; + if (!strcmp(yylval.gs->s, "0")) { + $$->u.expression.u.constant = 0; + } else if (sscanf(yylval.gs->s, "0%" WIDTH_o64_SCANF_IS_A_BROKEN_API SCNo64, + &$$->u.expression.u.constant) != 1) { + parse_error(parser_ctx, "cannot scanf octal constant"); + } + } + | HEXADECIMAL_CONSTANT + { + $$ = make_node(parser_ctx, NODE_EXPRESSION); + $$->u.expression.type = AST_EXP_CONSTANT; + if (sscanf(yylval.gs->s, "0x%" WIDTH_x64_SCANF_IS_A_BROKEN_API SCNx64, + &$$->u.expression.u.constant) != 1) { + parse_error(parser_ctx, "cannot scanf hexadecimal constant"); + } + } + | FLOAT_CONSTANT + { + $$ = make_node(parser_ctx, NODE_EXPRESSION); + $$->u.expression.type = AST_EXP_FLOAT_CONSTANT; + if (sscanf(yylval.gs->s, "%" WIDTH_lg_SCANF_IS_A_BROKEN_API "lg", + &$$->u.expression.u.float_constant) != 1) { + parse_error(parser_ctx, "cannot scanf float constant"); + } + } + | STRING_LITERAL_START DQUOTE + { + $$ = make_node(parser_ctx, NODE_EXPRESSION); + $$->u.expression.type = AST_EXP_STRING; + $$->u.expression.u.string = ""; + } + | STRING_LITERAL_START s_char_sequence DQUOTE + { + $$ = make_node(parser_ctx, NODE_EXPRESSION); + $$->u.expression.type = AST_EXP_STRING; + $$->u.expression.u.string = $2->s; + } + | CHARACTER_CONSTANT_START c_char_sequence SQUOTE + { + $$ = make_node(parser_ctx, NODE_EXPRESSION); + $$->u.expression.type = AST_EXP_STRING; + $$->u.expression.u.string = $2->s; + } + | LPAREN expression RPAREN + { + $$ = make_node(parser_ctx, NODE_EXPRESSION); + $$->u.expression.type = AST_EXP_NESTED; + $$->u.expression.u.child = $2; + } + ; + +identifiers + : IDENTIFIER + { + $$ = make_node(parser_ctx, NODE_EXPRESSION); + $$->u.expression.type = AST_EXP_IDENTIFIER; + $$->u.expression.u.identifier = yylval.gs->s; + } + | GLOBAL_IDENTIFIER + { + $$ = make_node(parser_ctx, NODE_EXPRESSION); + $$->u.expression.type = AST_EXP_GLOBAL_IDENTIFIER; + $$->u.expression.u.identifier = yylval.gs->s; + } + ; + +prefix_expression_rec + : LSBRAC unary_expression RSBRAC + { + $$ = $2; + } + | LSBRAC unary_expression RSBRAC prefix_expression_rec + { + $$ = $2; + $$->u.expression.pre_op = AST_LINK_BRACKET; + $$->u.expression.prev = $4; + } + ; + +prefix_expression + : identifiers + { + $$ = $1; + } + | identifiers prefix_expression_rec + { + $$ = $1; + $$->u.expression.pre_op = AST_LINK_BRACKET; + $$->u.expression.next_bracket = $2; + } + ; + +postfix_expression + : prefix_expression + { + $$ = $1; + } + | postfix_expression DOT prefix_expression + { + $$ = $3; + $$->u.expression.post_op = AST_LINK_DOT; + $$->u.expression.prev = $1; + } + | postfix_expression RARROW prefix_expression + { + $$ = $3; + $$->u.expression.post_op = AST_LINK_RARROW; + $$->u.expression.prev = $1; + } + ; + +unary_expression + : postfix_expression + { $$ = $1; } + | primary_expression + { $$ = $1; } + | unary_operator unary_expression + { + $$ = $1; + $$->u.unary_op.child = $2; + } + ; + +unary_operator + : PLUS + { + $$ = make_node(parser_ctx, NODE_UNARY_OP); + $$->u.unary_op.type = AST_UNARY_PLUS; + } + | MINUS + { + $$ = make_node(parser_ctx, NODE_UNARY_OP); + $$->u.unary_op.type = AST_UNARY_MINUS; + } + | NOT_OP + { + $$ = make_node(parser_ctx, NODE_UNARY_OP); + $$->u.unary_op.type = AST_UNARY_NOT; + } + | NOT_BIN + { + $$ = make_node(parser_ctx, NODE_UNARY_OP); + $$->u.unary_op.type = AST_UNARY_BIT_NOT; + } + ; + +multiplicative_expression + : unary_expression + { $$ = $1; } + | multiplicative_expression STAR unary_expression + { + $$ = make_op_node(parser_ctx, AST_OP_MUL, $1, $3); + } + | multiplicative_expression DIV_OP unary_expression + { + $$ = make_op_node(parser_ctx, AST_OP_DIV, $1, $3); + } + | multiplicative_expression MOD_OP unary_expression + { + $$ = make_op_node(parser_ctx, AST_OP_MOD, $1, $3); + } + ; + +additive_expression + : multiplicative_expression + { $$ = $1; } + | additive_expression PLUS multiplicative_expression + { + $$ = make_op_node(parser_ctx, AST_OP_PLUS, $1, $3); + } + | additive_expression MINUS multiplicative_expression + { + $$ = make_op_node(parser_ctx, AST_OP_MINUS, $1, $3); + } + ; + +shift_expression + : additive_expression + { $$ = $1; } + | shift_expression LEFT_OP additive_expression + { + $$ = make_op_node(parser_ctx, AST_OP_BIT_LSHIFT, $1, $3); + } + | shift_expression RIGHT_OP additive_expression + { + $$ = make_op_node(parser_ctx, AST_OP_BIT_RSHIFT, $1, $3); + } + ; + +and_expression + : shift_expression + { $$ = $1; } + | and_expression AND_BIN shift_expression + { + $$ = make_op_node(parser_ctx, AST_OP_BIT_AND, $1, $3); + } + ; + +exclusive_or_expression + : and_expression + { $$ = $1; } + | exclusive_or_expression XOR_BIN and_expression + { + $$ = make_op_node(parser_ctx, AST_OP_BIT_XOR, $1, $3); + } + ; + +inclusive_or_expression + : exclusive_or_expression + { $$ = $1; } + | inclusive_or_expression OR_BIN exclusive_or_expression + { + $$ = make_op_node(parser_ctx, AST_OP_BIT_OR, $1, $3); + } + ; + +relational_expression + : inclusive_or_expression + { $$ = $1; } + | relational_expression LT_OP inclusive_or_expression + { + $$ = make_op_node(parser_ctx, AST_OP_LT, $1, $3); + } + | relational_expression GT_OP inclusive_or_expression + { + $$ = make_op_node(parser_ctx, AST_OP_GT, $1, $3); + } + | relational_expression LE_OP inclusive_or_expression + { + $$ = make_op_node(parser_ctx, AST_OP_LE, $1, $3); + } + | relational_expression GE_OP inclusive_or_expression + { + $$ = make_op_node(parser_ctx, AST_OP_GE, $1, $3); + } + ; + +equality_expression + : relational_expression + { $$ = $1; } + | equality_expression EQ_OP relational_expression + { + $$ = make_op_node(parser_ctx, AST_OP_EQ, $1, $3); + } + | equality_expression NE_OP relational_expression + { + $$ = make_op_node(parser_ctx, AST_OP_NE, $1, $3); + } + ; + +logical_and_expression + : equality_expression + { $$ = $1; } + | logical_and_expression AND_OP equality_expression + { + $$ = make_op_node(parser_ctx, AST_OP_AND, $1, $3); + } + ; + +logical_or_expression + : logical_and_expression + { $$ = $1; } + | logical_or_expression OR_OP logical_and_expression + { + $$ = make_op_node(parser_ctx, AST_OP_OR, $1, $3); + } + ; + +expression + : logical_or_expression + { $$ = $1; } + ; + +translation_unit + : expression + { + parser_ctx->ast->root.u.root.child = $1; + } + ; diff --git a/src/common/filter/filter-visitor-generate-bytecode.c b/src/common/filter/filter-visitor-generate-bytecode.c deleted file mode 100644 index fe1220305..000000000 --- a/src/common/filter/filter-visitor-generate-bytecode.c +++ /dev/null @@ -1,670 +0,0 @@ -/* - * filter-visitor-generate-bytecode.c - * - * LTTng filter bytecode generation - * - * Copyright 2012 Mathieu Desnoyers - * - * SPDX-License-Identifier: LGPL-2.1-only - * - */ - -#include -#include -#include -#include -#include - -#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; -} diff --git a/src/common/filter/filter-visitor-generate-bytecode.cpp b/src/common/filter/filter-visitor-generate-bytecode.cpp new file mode 100644 index 000000000..7b418acdc --- /dev/null +++ b/src/common/filter/filter-visitor-generate-bytecode.cpp @@ -0,0 +1,670 @@ +/* + * filter-visitor-generate-bytecode.c + * + * LTTng filter bytecode generation + * + * Copyright 2012 Mathieu Desnoyers + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include + +#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; +} diff --git a/src/common/filter/filter-visitor-generate-ir.c b/src/common/filter/filter-visitor-generate-ir.c deleted file mode 100644 index 64e41ec93..000000000 --- a/src/common/filter/filter-visitor-generate-ir.c +++ /dev/null @@ -1,911 +0,0 @@ -/* - * filter-visitor-generate-ir.c - * - * LTTng filter generate intermediate representation - * - * Copyright 2012 Mathieu Desnoyers - * - * SPDX-License-Identifier: LGPL-2.1-only - * - */ - -#include -#include -#include -#include -#include -#include "filter-ast.h" -#include "filter-parser.h" -#include "filter-ir.h" - -#include -#include -#include - -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; -} diff --git a/src/common/filter/filter-visitor-generate-ir.cpp b/src/common/filter/filter-visitor-generate-ir.cpp new file mode 100644 index 000000000..a109ca60a --- /dev/null +++ b/src/common/filter/filter-visitor-generate-ir.cpp @@ -0,0 +1,911 @@ +/* + * filter-visitor-generate-ir.c + * + * LTTng filter generate intermediate representation + * + * Copyright 2012 Mathieu Desnoyers + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include +#include "filter-ast.h" +#include "filter-parser.hpp" +#include "filter-ir.h" + +#include +#include +#include + +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; +} diff --git a/src/common/filter/filter-visitor-ir-check-binary-comparator.c b/src/common/filter/filter-visitor-ir-check-binary-comparator.c deleted file mode 100644 index 19e594311..000000000 --- a/src/common/filter/filter-visitor-ir-check-binary-comparator.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * filter-visitor-ir-check-binary-comparator.c - * - * LTTng filter IR check binary comparator - * - * Copyright 2012 Mathieu Desnoyers - * - * SPDX-License-Identifier: LGPL-2.1-only - * - */ - -#include -#include -#include -#include -#include - -#include - -#include "filter-ast.h" -#include "filter-parser.h" -#include "filter-ir.h" - -static -int check_bin_comparator(struct ir_op *node) -{ - switch (node->op) { - case IR_OP_UNKNOWN: - default: - fprintf(stderr, "[error] %s: unknown op type\n", __func__); - return -EINVAL; - - case IR_OP_ROOT: - return check_bin_comparator(node->u.root.child); - case IR_OP_LOAD: - return 0; - case IR_OP_UNARY: - return check_bin_comparator(node->u.unary.child); - case IR_OP_BINARY: - { - int ret; - - if (node->u.binary.left->data_type == IR_DATA_STRING - || node->u.binary.right->data_type - == IR_DATA_STRING) { - if (node->u.binary.type != AST_OP_EQ - && node->u.binary.type != AST_OP_NE) { - fprintf(stderr, "[error] Only '==' and '!=' comparators are allowed for strings\n"); - return -EINVAL; - } - } - - ret = check_bin_comparator(node->u.binary.left); - if (ret) - return ret; - return check_bin_comparator(node->u.binary.right); - } - case IR_OP_LOGICAL: - { - int ret; - - ret = check_bin_comparator(node->u.logical.left); - if (ret) - return ret; - return check_bin_comparator(node->u.logical.right); - } - } -} - -int filter_visitor_ir_check_binary_comparator(struct filter_parser_ctx *ctx) -{ - return check_bin_comparator(ctx->ir_root); -} diff --git a/src/common/filter/filter-visitor-ir-check-binary-comparator.cpp b/src/common/filter/filter-visitor-ir-check-binary-comparator.cpp new file mode 100644 index 000000000..480100f25 --- /dev/null +++ b/src/common/filter/filter-visitor-ir-check-binary-comparator.cpp @@ -0,0 +1,73 @@ +/* + * filter-visitor-ir-check-binary-comparator.c + * + * LTTng filter IR check binary comparator + * + * Copyright 2012 Mathieu Desnoyers + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include + +#include + +#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); +} diff --git a/src/common/filter/filter-visitor-ir-check-binary-op-nesting.c b/src/common/filter/filter-visitor-ir-check-binary-op-nesting.c deleted file mode 100644 index fed236322..000000000 --- a/src/common/filter/filter-visitor-ir-check-binary-op-nesting.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * filter-visitor-ir-check-binary-op-nesting.c - * - * LTTng filter IR check binary op nesting - * - * Copyright 2012 Mathieu Desnoyers - * - * SPDX-License-Identifier: LGPL-2.1-only - * - */ - -#include -#include -#include -#include -#include -#include "filter-ast.h" -#include "filter-parser.h" -#include "filter-ir.h" - -#include -#include - -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); -} diff --git a/src/common/filter/filter-visitor-ir-check-binary-op-nesting.cpp b/src/common/filter/filter-visitor-ir-check-binary-op-nesting.cpp new file mode 100644 index 000000000..290ea0367 --- /dev/null +++ b/src/common/filter/filter-visitor-ir-check-binary-op-nesting.cpp @@ -0,0 +1,69 @@ +/* + * filter-visitor-ir-check-binary-op-nesting.c + * + * LTTng filter IR check binary op nesting + * + * Copyright 2012 Mathieu Desnoyers + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include +#include "filter-ast.h" +#include "filter-parser.hpp" +#include "filter-ir.h" + +#include +#include + +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); +} diff --git a/src/common/filter/filter-visitor-ir-normalize-glob-patterns.c b/src/common/filter/filter-visitor-ir-normalize-glob-patterns.c deleted file mode 100644 index 999fc2ea1..000000000 --- a/src/common/filter/filter-visitor-ir-normalize-glob-patterns.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * filter-visitor-ir-normalize-glob-patterns.c - * - * LTTng filter IR normalize string - * - * Copyright 2017 Philippe Proulx - * - * SPDX-License-Identifier: LGPL-2.1-only - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#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); -} diff --git a/src/common/filter/filter-visitor-ir-normalize-glob-patterns.cpp b/src/common/filter/filter-visitor-ir-normalize-glob-patterns.cpp new file mode 100644 index 000000000..a091b8123 --- /dev/null +++ b/src/common/filter/filter-visitor-ir-normalize-glob-patterns.cpp @@ -0,0 +1,82 @@ +/* + * filter-visitor-ir-normalize-glob-patterns.c + * + * LTTng filter IR normalize string + * + * Copyright 2017 Philippe Proulx + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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); +} diff --git a/src/common/filter/filter-visitor-ir-validate-globbing.c b/src/common/filter/filter-visitor-ir-validate-globbing.c deleted file mode 100644 index 74bb72db4..000000000 --- a/src/common/filter/filter-visitor-ir-validate-globbing.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * filter-visitor-ir-validate-globbing.c - * - * LTTng filter IR validate globbing - * - * Copyright 2017 Philippe Proulx - * - * SPDX-License-Identifier: LGPL-2.1-only - * - */ - -#include -#include -#include -#include -#include - -#include -#include - -#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); -} diff --git a/src/common/filter/filter-visitor-ir-validate-globbing.cpp b/src/common/filter/filter-visitor-ir-validate-globbing.cpp new file mode 100644 index 000000000..8f9c785c4 --- /dev/null +++ b/src/common/filter/filter-visitor-ir-validate-globbing.cpp @@ -0,0 +1,110 @@ +/* + * filter-visitor-ir-validate-globbing.c + * + * LTTng filter IR validate globbing + * + * Copyright 2017 Philippe Proulx + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#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); +} diff --git a/src/common/filter/filter-visitor-ir-validate-string.c b/src/common/filter/filter-visitor-ir-validate-string.c deleted file mode 100644 index 19018456c..000000000 --- a/src/common/filter/filter-visitor-ir-validate-string.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * filter-visitor-ir-validate-string.c - * - * LTTng filter IR validate string - * - * Copyright 2014 Jérémie Galarneau - * - * SPDX-License-Identifier: LGPL-2.1-only - * - */ - -#include -#include -#include -#include -#include - -#include -#include - -#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); -} diff --git a/src/common/filter/filter-visitor-ir-validate-string.cpp b/src/common/filter/filter-visitor-ir-validate-string.cpp new file mode 100644 index 000000000..0c18f98bc --- /dev/null +++ b/src/common/filter/filter-visitor-ir-validate-string.cpp @@ -0,0 +1,122 @@ +/* + * filter-visitor-ir-validate-string.c + * + * LTTng filter IR validate string + * + * Copyright 2014 Jérémie Galarneau + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#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); +} diff --git a/src/common/filter/filter-visitor-xml.c b/src/common/filter/filter-visitor-xml.c deleted file mode 100644 index 7d6094e4c..000000000 --- a/src/common/filter/filter-visitor-xml.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * filter-visitor-xml.c - * - * LTTng filter XML pretty printer visitor - * - * Copyright 2012 Mathieu Desnoyers - * - * SPDX-License-Identifier: LGPL-2.1-only - * - */ - -#include -#include -#include -#include -#include -#include "filter-ast.h" -#include "filter-parser.h" - -#include -#include - -#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, "\n", - node->u.expression.u.string); - break; - case AST_EXP_CONSTANT: - print_tabs(stream, indent); - fprintf(stream, "\n", - node->u.expression.u.constant); - break; - case AST_EXP_FLOAT_CONSTANT: - print_tabs(stream, indent); - fprintf(stream, "\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, "\n"); - if (recursive_visit_print_expression(iter_node, - stream, indent + 1)) { - return -EINVAL; - } - print_tabs(stream, indent); - fprintf(stream, "\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, "\n"); - ret = recursive_visit_print(node->u.root.child, stream, - indent + 1); - print_tabs(stream, indent); - fprintf(stream, "\n"); - return ret; - case NODE_EXPRESSION: - print_tabs(stream, indent); - fprintf(stream, "\n"); - ret = recursive_visit_print_expression(node, stream, - indent + 1); - print_tabs(stream, indent); - fprintf(stream, "\n"); - return ret; - case NODE_OP: - print_tabs(stream, indent); - 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, "\n"); - return ret; - case NODE_UNARY_OP: - print_tabs(stream, indent); - fprintf(stream, "\n"); - ret = recursive_visit_print(node->u.unary_op.child, - stream, indent + 1); - print_tabs(stream, indent); - fprintf(stream, "\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); -} diff --git a/src/common/filter/filter-visitor-xml.cpp b/src/common/filter/filter-visitor-xml.cpp new file mode 100644 index 000000000..eb12452a6 --- /dev/null +++ b/src/common/filter/filter-visitor-xml.cpp @@ -0,0 +1,237 @@ +/* + * filter-visitor-xml.c + * + * LTTng filter XML pretty printer visitor + * + * Copyright 2012 Mathieu Desnoyers + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include +#include "filter-ast.h" +#include "filter-parser.hpp" + +#include +#include + +#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, "\n", + node->u.expression.u.string); + break; + case AST_EXP_CONSTANT: + print_tabs(stream, indent); + fprintf(stream, "\n", + node->u.expression.u.constant); + break; + case AST_EXP_FLOAT_CONSTANT: + print_tabs(stream, indent); + fprintf(stream, "\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, "\n"); + if (recursive_visit_print_expression(iter_node, + stream, indent + 1)) { + return -EINVAL; + } + print_tabs(stream, indent); + fprintf(stream, "\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, "\n"); + ret = recursive_visit_print(node->u.root.child, stream, + indent + 1); + print_tabs(stream, indent); + fprintf(stream, "\n"); + return ret; + case NODE_EXPRESSION: + print_tabs(stream, indent); + fprintf(stream, "\n"); + ret = recursive_visit_print_expression(node, stream, + indent + 1); + print_tabs(stream, indent); + fprintf(stream, "\n"); + return ret; + case NODE_OP: + print_tabs(stream, indent); + 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, "\n"); + return ret; + case NODE_UNARY_OP: + print_tabs(stream, indent); + fprintf(stream, "\n"); + ret = recursive_visit_print(node->u.unary_op.child, + stream, indent + 1); + print_tabs(stream, indent); + fprintf(stream, "\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); +} diff --git a/src/lib/lttng-ctl/lttng-ctl.cpp b/src/lib/lttng-ctl/lttng-ctl.cpp index 362298718..d4ec1c81b 100644 --- a/src/lib/lttng-ctl/lttng-ctl.cpp +++ b/src/lib/lttng-ctl/lttng-ctl.cpp @@ -47,7 +47,7 @@ #include "lttng-ctl-helper.h" #include -#include +#include #include #define COPY_DOMAIN_PACKED(dst, src) \