From: Philippe Proulx Date: Fri, 17 Feb 2017 09:14:40 +0000 (-0500) Subject: Filtering: add support for star-only globbing patterns X-Git-Tag: v2.10.0-rc1~16 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=3151a51df2b93554f3e4559a2e7ec08541e8674d;p=lttng-ust.git Filtering: add support for star-only globbing patterns This patch adds the support for "full" star-only globbing patterns to be used in filter literal strings. A star-only globbing pattern is a globbing pattern with the star (`*`) being the only special character. This means `?` and character sets (`[abc-k]`) are not supported here. We cannot support them without a strategy to differentiate the globbing pattern because `?` and `[` are not special characters in filter literal strings right now. The eventual strategy to support them would probably look like this: filename =* "?sys*.[ch]" The filter bytecode generator in LTTng-tools's session daemon creates the new FILTER_OP_LOAD_STAR_GLOB_STRING operation when the interpreter should load a star globbing pattern literal string. Even if both "plain", or legacy strings and star globbing pattern strings are literal strings, they do not represent the same thing, that is, the == and != operators act differently. The validation process checks that: 1. There's no binary operator between two FILTER_OP_LOAD_STAR_GLOB_STRING operations. It is illegal to compare two star globbing patterns, as this is not trivial to implement, and completely useless as far as I know. 2. Only the == and != binary operators are allowed between a star globbing pattern and a string. For the special case of star globbing patterns with a star at the end only, the current behaviour is not changed to preserve a maximum of backward compatibility. This is also why the UST ABI version is changed from 7.1 to 7.2, not to 8.0. == or != operations between REG_STRING and REG_STAR_GLOB_STRING registers is specialized to FILTER_OP_EQ_STAR_GLOB_STRING and FILTER_OP_NE_STAR_GLOB_STRING. Which side is the actual globbing pattern (the one with the REG_STAR_GLOB_STRING type) is checked at execution time. The strutils_star_glob_match() function is used to perform the match operation. See the implementation for more details. Signed-off-by: Philippe Proulx Signed-off-by: Mathieu Desnoyers --- diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 6e8f8d7b..f76d2a9f 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -43,7 +43,7 @@ /* Version for ABI between liblttng-ust, sessiond, consumerd */ #define LTTNG_UST_ABI_MAJOR_VERSION 7 -#define LTTNG_UST_ABI_MINOR_VERSION 1 +#define LTTNG_UST_ABI_MINOR_VERSION 2 enum lttng_ust_instrumentation { LTTNG_UST_TRACEPOINT = 0, diff --git a/liblttng-ust/filter-bytecode.h b/liblttng-ust/filter-bytecode.h index d5194bc2..b0c8f818 100644 --- a/liblttng-ust/filter-bytecode.h +++ b/liblttng-ust/filter-bytecode.h @@ -51,106 +51,120 @@ struct literal_string { } __attribute__((packed)); enum filter_op { - FILTER_OP_UNKNOWN = 0, + FILTER_OP_UNKNOWN = 0, - FILTER_OP_RETURN, + FILTER_OP_RETURN = 1, /* binary */ - FILTER_OP_MUL, - FILTER_OP_DIV, - FILTER_OP_MOD, - FILTER_OP_PLUS, - FILTER_OP_MINUS, - FILTER_OP_RSHIFT, - FILTER_OP_LSHIFT, - FILTER_OP_BIN_AND, - FILTER_OP_BIN_OR, - FILTER_OP_BIN_XOR, + FILTER_OP_MUL = 2, + FILTER_OP_DIV = 3, + FILTER_OP_MOD = 4, + FILTER_OP_PLUS = 5, + FILTER_OP_MINUS = 6, + FILTER_OP_RSHIFT = 7, + FILTER_OP_LSHIFT = 8, + FILTER_OP_BIN_AND = 9, + FILTER_OP_BIN_OR = 10, + FILTER_OP_BIN_XOR = 11, /* binary comparators */ - FILTER_OP_EQ, - FILTER_OP_NE, - FILTER_OP_GT, - FILTER_OP_LT, - FILTER_OP_GE, - FILTER_OP_LE, - - /* string binary comparator */ - FILTER_OP_EQ_STRING, - FILTER_OP_NE_STRING, - FILTER_OP_GT_STRING, - FILTER_OP_LT_STRING, - FILTER_OP_GE_STRING, - FILTER_OP_LE_STRING, + FILTER_OP_EQ = 12, + FILTER_OP_NE = 13, + FILTER_OP_GT = 14, + FILTER_OP_LT = 15, + FILTER_OP_GE = 16, + FILTER_OP_LE = 17, + + /* string binary comparator: apply to */ + FILTER_OP_EQ_STRING = 18, + FILTER_OP_NE_STRING = 19, + FILTER_OP_GT_STRING = 20, + FILTER_OP_LT_STRING = 21, + FILTER_OP_GE_STRING = 22, + FILTER_OP_LE_STRING = 23, /* s64 binary comparator */ - FILTER_OP_EQ_S64, - FILTER_OP_NE_S64, - FILTER_OP_GT_S64, - FILTER_OP_LT_S64, - FILTER_OP_GE_S64, - FILTER_OP_LE_S64, + FILTER_OP_EQ_S64 = 24, + FILTER_OP_NE_S64 = 25, + FILTER_OP_GT_S64 = 26, + FILTER_OP_LT_S64 = 27, + FILTER_OP_GE_S64 = 28, + FILTER_OP_LE_S64 = 29, /* double binary comparator */ - FILTER_OP_EQ_DOUBLE, - FILTER_OP_NE_DOUBLE, - FILTER_OP_GT_DOUBLE, - FILTER_OP_LT_DOUBLE, - FILTER_OP_GE_DOUBLE, - FILTER_OP_LE_DOUBLE, + FILTER_OP_EQ_DOUBLE = 30, + FILTER_OP_NE_DOUBLE = 31, + FILTER_OP_GT_DOUBLE = 32, + FILTER_OP_LT_DOUBLE = 33, + FILTER_OP_GE_DOUBLE = 34, + FILTER_OP_LE_DOUBLE = 35, /* Mixed S64-double binary comparators */ - FILTER_OP_EQ_DOUBLE_S64, - FILTER_OP_NE_DOUBLE_S64, - FILTER_OP_GT_DOUBLE_S64, - FILTER_OP_LT_DOUBLE_S64, - FILTER_OP_GE_DOUBLE_S64, - FILTER_OP_LE_DOUBLE_S64, - - FILTER_OP_EQ_S64_DOUBLE, - FILTER_OP_NE_S64_DOUBLE, - FILTER_OP_GT_S64_DOUBLE, - FILTER_OP_LT_S64_DOUBLE, - FILTER_OP_GE_S64_DOUBLE, - FILTER_OP_LE_S64_DOUBLE, + FILTER_OP_EQ_DOUBLE_S64 = 36, + FILTER_OP_NE_DOUBLE_S64 = 37, + FILTER_OP_GT_DOUBLE_S64 = 38, + FILTER_OP_LT_DOUBLE_S64 = 39, + FILTER_OP_GE_DOUBLE_S64 = 40, + FILTER_OP_LE_DOUBLE_S64 = 41, + + FILTER_OP_EQ_S64_DOUBLE = 42, + FILTER_OP_NE_S64_DOUBLE = 43, + FILTER_OP_GT_S64_DOUBLE = 44, + FILTER_OP_LT_S64_DOUBLE = 45, + FILTER_OP_GE_S64_DOUBLE = 46, + FILTER_OP_LE_S64_DOUBLE = 47, /* unary */ - FILTER_OP_UNARY_PLUS, - FILTER_OP_UNARY_MINUS, - FILTER_OP_UNARY_NOT, - FILTER_OP_UNARY_PLUS_S64, - FILTER_OP_UNARY_MINUS_S64, - FILTER_OP_UNARY_NOT_S64, - FILTER_OP_UNARY_PLUS_DOUBLE, - FILTER_OP_UNARY_MINUS_DOUBLE, - FILTER_OP_UNARY_NOT_DOUBLE, + FILTER_OP_UNARY_PLUS = 48, + FILTER_OP_UNARY_MINUS = 49, + FILTER_OP_UNARY_NOT = 50, + FILTER_OP_UNARY_PLUS_S64 = 51, + FILTER_OP_UNARY_MINUS_S64 = 52, + FILTER_OP_UNARY_NOT_S64 = 53, + FILTER_OP_UNARY_PLUS_DOUBLE = 54, + FILTER_OP_UNARY_MINUS_DOUBLE = 55, + FILTER_OP_UNARY_NOT_DOUBLE = 56, /* logical */ - FILTER_OP_AND, - FILTER_OP_OR, + FILTER_OP_AND = 57, + FILTER_OP_OR = 58, /* load field ref */ - FILTER_OP_LOAD_FIELD_REF, - FILTER_OP_LOAD_FIELD_REF_STRING, - FILTER_OP_LOAD_FIELD_REF_SEQUENCE, - FILTER_OP_LOAD_FIELD_REF_S64, - FILTER_OP_LOAD_FIELD_REF_DOUBLE, + FILTER_OP_LOAD_FIELD_REF = 59, + FILTER_OP_LOAD_FIELD_REF_STRING = 60, + FILTER_OP_LOAD_FIELD_REF_SEQUENCE = 61, + FILTER_OP_LOAD_FIELD_REF_S64 = 62, + FILTER_OP_LOAD_FIELD_REF_DOUBLE = 63, /* load immediate from operand */ - FILTER_OP_LOAD_STRING, - FILTER_OP_LOAD_S64, - FILTER_OP_LOAD_DOUBLE, + FILTER_OP_LOAD_STRING = 64, + FILTER_OP_LOAD_S64 = 65, + FILTER_OP_LOAD_DOUBLE = 66, /* cast */ - FILTER_OP_CAST_TO_S64, - FILTER_OP_CAST_DOUBLE_TO_S64, - FILTER_OP_CAST_NOP, + FILTER_OP_CAST_TO_S64 = 67, + FILTER_OP_CAST_DOUBLE_TO_S64 = 68, + FILTER_OP_CAST_NOP = 69, /* get context ref */ - FILTER_OP_GET_CONTEXT_REF, - FILTER_OP_GET_CONTEXT_REF_STRING, - FILTER_OP_GET_CONTEXT_REF_S64, - FILTER_OP_GET_CONTEXT_REF_DOUBLE, + FILTER_OP_GET_CONTEXT_REF = 70, + FILTER_OP_GET_CONTEXT_REF_STRING = 71, + FILTER_OP_GET_CONTEXT_REF_S64 = 72, + FILTER_OP_GET_CONTEXT_REF_DOUBLE = 73, + + /* load userspace field ref */ + FILTER_OP_LOAD_FIELD_REF_USER_STRING = 74, + FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE = 75, + + /* + * load immediate star globbing pattern (literal string) + * from immediate + */ + FILTER_OP_LOAD_STAR_GLOB_STRING = 76, + + /* globbing pattern binary operator: apply to */ + FILTER_OP_EQ_STAR_GLOB_STRING = 77, + FILTER_OP_NE_STAR_GLOB_STRING = 78, NR_FILTER_OPS, }; diff --git a/liblttng-ust/lttng-filter-interpreter.c b/liblttng-ust/lttng-filter-interpreter.c index 0caeab6f..afea3f15 100644 --- a/liblttng-ust/lttng-filter-interpreter.c +++ b/liblttng-ust/lttng-filter-interpreter.c @@ -27,6 +27,7 @@ #define _LGPL_SOURCE #include #include "lttng-filter.h" +#include "string-utils.h" /* * -1: wildcard found. @@ -54,6 +55,46 @@ int parse_char(const char **p) } } +/* + * Returns -1ULL if the string is null-terminated, or the number of + * characters if not. + */ +static +size_t get_str_or_seq_len(const struct estack_entry *entry) +{ + if (entry->u.s.seq_len == UINT_MAX) { + return -1ULL; + } else { + return entry->u.s.seq_len; + } +} + +static +int stack_star_glob_match(struct estack *stack, int top, const char *cmp_type) +{ + const char *pattern; + const char *candidate; + size_t pattern_len; + size_t candidate_len; + + /* Find out which side is the pattern vs. the candidate. */ + if (estack_ax(stack, top)->u.s.literal_type == ESTACK_STRING_LITERAL_TYPE_STAR_GLOB) { + pattern = estack_ax(stack, top)->u.s.str; + pattern_len = get_str_or_seq_len(estack_ax(stack, top)); + candidate = estack_bx(stack, top)->u.s.str; + candidate_len = get_str_or_seq_len(estack_bx(stack, top)); + } else { + pattern = estack_bx(stack, top)->u.s.str; + pattern_len = get_str_or_seq_len(estack_bx(stack, top)); + candidate = estack_ax(stack, top)->u.s.str; + candidate_len = get_str_or_seq_len(estack_ax(stack, top)); + } + + /* Perform the match. Returns 0 when the result is true. */ + return !strutils_star_glob_match(pattern, pattern_len, candidate, + candidate_len); +} + static int stack_strcmp(struct estack *stack, int top, const char *cmp_type) { @@ -68,7 +109,8 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) if (q - estack_ax(stack, top)->u.s.str >= estack_ax(stack, top)->u.s.seq_len || *q == '\0') { return 0; } else { - if (estack_ax(stack, top)->u.s.literal) { + if (estack_ax(stack, top)->u.s.literal_type == + ESTACK_STRING_LITERAL_TYPE_PLAIN) { ret = parse_char(&q); if (ret == -1) return 0; @@ -77,14 +119,16 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) } } if (unlikely(q - estack_ax(stack, top)->u.s.str >= estack_ax(stack, top)->u.s.seq_len || *q == '\0')) { - if (estack_bx(stack, top)->u.s.literal) { + if (estack_bx(stack, top)->u.s.literal_type == + ESTACK_STRING_LITERAL_TYPE_PLAIN) { ret = parse_char(&p); if (ret == -1) return 0; } return 1; } - if (estack_bx(stack, top)->u.s.literal) { + if (estack_bx(stack, top)->u.s.literal_type == + ESTACK_STRING_LITERAL_TYPE_PLAIN) { ret = parse_char(&p); if (ret == -1) { return 0; @@ -93,7 +137,8 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) } /* else compare both char */ } - if (estack_ax(stack, top)->u.s.literal) { + if (estack_ax(stack, top)->u.s.literal_type == + ESTACK_STRING_LITERAL_TYPE_PLAIN) { ret = parse_char(&q); if (ret == -1) { return 0; @@ -228,6 +273,10 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, [ FILTER_OP_GE_STRING ] = &&LABEL_FILTER_OP_GE_STRING, [ FILTER_OP_LE_STRING ] = &&LABEL_FILTER_OP_LE_STRING, + /* globbing pattern binary comparator */ + [ FILTER_OP_EQ_STAR_GLOB_STRING ] = &&LABEL_FILTER_OP_EQ_STAR_GLOB_STRING, + [ FILTER_OP_NE_STAR_GLOB_STRING ] = &&LABEL_FILTER_OP_NE_STAR_GLOB_STRING, + /* s64 binary comparator */ [ FILTER_OP_EQ_S64 ] = &&LABEL_FILTER_OP_EQ_S64, [ FILTER_OP_NE_S64 ] = &&LABEL_FILTER_OP_NE_S64, @@ -283,6 +332,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, /* load from immediate operand */ [ FILTER_OP_LOAD_STRING ] = &&LABEL_FILTER_OP_LOAD_STRING, + [ FILTER_OP_LOAD_STAR_GLOB_STRING ] = &&LABEL_FILTER_OP_LOAD_STAR_GLOB_STRING, [ FILTER_OP_LOAD_S64 ] = &&LABEL_FILTER_OP_LOAD_S64, [ FILTER_OP_LOAD_DOUBLE ] = &&LABEL_FILTER_OP_LOAD_DOUBLE, @@ -343,7 +393,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_EQ_S64); case REG_DOUBLE: JUMP_TO(FILTER_OP_EQ_DOUBLE_S64); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -359,7 +410,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_EQ_S64_DOUBLE); case REG_DOUBLE: JUMP_TO(FILTER_OP_EQ_DOUBLE); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -377,6 +429,26 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, goto end; case REG_STRING: JUMP_TO(FILTER_OP_EQ_STRING); + case REG_STAR_GLOB_STRING: + JUMP_TO(FILTER_OP_EQ_STAR_GLOB_STRING); + default: + ERR("Unknown filter register type (%d)", + (int) estack_bx_t); + ret = -EINVAL; + goto end; + } + break; + case REG_STAR_GLOB_STRING: + switch (estack_bx_t) { + case REG_S64: /* Fall-through */ + case REG_DOUBLE: + ret = -EINVAL; + goto end; + case REG_STRING: + JUMP_TO(FILTER_OP_EQ_STAR_GLOB_STRING); + case REG_STAR_GLOB_STRING: + ret = -EINVAL; + goto end; default: ERR("Unknown filter register type (%d)", (int) estack_bx_t); @@ -401,7 +473,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_NE_S64); case REG_DOUBLE: JUMP_TO(FILTER_OP_NE_DOUBLE_S64); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -417,7 +490,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_NE_S64_DOUBLE); case REG_DOUBLE: JUMP_TO(FILTER_OP_NE_DOUBLE); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -435,6 +509,26 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, goto end; case REG_STRING: JUMP_TO(FILTER_OP_NE_STRING); + case REG_STAR_GLOB_STRING: + JUMP_TO(FILTER_OP_NE_STAR_GLOB_STRING); + default: + ERR("Unknown filter register type (%d)", + (int) estack_bx_t); + ret = -EINVAL; + goto end; + } + break; + case REG_STAR_GLOB_STRING: + switch (estack_bx_t) { + case REG_S64: /* Fall-through */ + case REG_DOUBLE: + ret = -EINVAL; + goto end; + case REG_STRING: + JUMP_TO(FILTER_OP_NE_STAR_GLOB_STRING); + case REG_STAR_GLOB_STRING: + ret = -EINVAL; + goto end; default: ERR("Unknown filter register type (%d)", (int) estack_bx_t); @@ -459,7 +553,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_GT_S64); case REG_DOUBLE: JUMP_TO(FILTER_OP_GT_DOUBLE_S64); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -475,7 +570,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_GT_S64_DOUBLE); case REG_DOUBLE: JUMP_TO(FILTER_OP_GT_DOUBLE); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -488,7 +584,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, case REG_STRING: switch (estack_bx_t) { case REG_S64: /* Fall-through */ - case REG_DOUBLE: + case REG_DOUBLE: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; case REG_STRING: @@ -517,7 +614,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_LT_S64); case REG_DOUBLE: JUMP_TO(FILTER_OP_LT_DOUBLE_S64); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -533,7 +631,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_LT_S64_DOUBLE); case REG_DOUBLE: JUMP_TO(FILTER_OP_LT_DOUBLE); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -546,7 +645,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, case REG_STRING: switch (estack_bx_t) { case REG_S64: /* Fall-through */ - case REG_DOUBLE: + case REG_DOUBLE: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; case REG_STRING: @@ -575,7 +675,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_GE_S64); case REG_DOUBLE: JUMP_TO(FILTER_OP_GE_DOUBLE_S64); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -591,7 +692,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_GE_S64_DOUBLE); case REG_DOUBLE: JUMP_TO(FILTER_OP_GE_DOUBLE); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -604,7 +706,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, case REG_STRING: switch (estack_bx_t) { case REG_S64: /* Fall-through */ - case REG_DOUBLE: + case REG_DOUBLE: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; case REG_STRING: @@ -633,7 +736,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_LE_S64); case REG_DOUBLE: JUMP_TO(FILTER_OP_LE_DOUBLE_S64); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -649,7 +753,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_LE_S64_DOUBLE); case REG_DOUBLE: JUMP_TO(FILTER_OP_LE_DOUBLE); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -662,7 +767,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, case REG_STRING: switch (estack_bx_t) { case REG_S64: /* Fall-through */ - case REG_DOUBLE: + case REG_DOUBLE: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; case REG_STRING: @@ -749,6 +855,29 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, PO; } + OP(FILTER_OP_EQ_STAR_GLOB_STRING): + { + int res; + + res = (stack_star_glob_match(stack, top, "==") == 0); + estack_pop(stack, top, ax, bx, ax_t, bx_t); + estack_ax_v = res; + estack_ax_t = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_NE_STAR_GLOB_STRING): + { + int res; + + res = (stack_star_glob_match(stack, top, "!=") != 0); + estack_pop(stack, top, ax, bx, ax_t, bx_t); + estack_ax_v = res; + estack_ax_t = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_EQ_S64): { int res; @@ -1027,7 +1156,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_UNARY_PLUS_S64); case REG_DOUBLE: JUMP_TO(FILTER_OP_UNARY_PLUS_DOUBLE); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -1045,7 +1175,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_UNARY_MINUS_S64); case REG_DOUBLE: JUMP_TO(FILTER_OP_UNARY_MINUS_DOUBLE); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -1063,7 +1194,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_UNARY_NOT_S64); case REG_DOUBLE: JUMP_TO(FILTER_OP_UNARY_NOT_DOUBLE); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -1169,7 +1301,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, goto end; } estack_ax(stack, top)->u.s.seq_len = UINT_MAX; - estack_ax(stack, top)->u.s.literal = 0; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; estack_ax_t = REG_STRING; dbg_printf("ref load string %s\n", estack_ax(stack, top)->u.s.str); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); @@ -1195,7 +1328,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, ret = -EINVAL; goto end; } - estack_ax(stack, top)->u.s.literal = 0; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; next_pc += sizeof(struct load_op) + sizeof(struct field_ref); PO; } @@ -1241,12 +1375,28 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax(stack, top)->u.s.str = insn->data; estack_ax(stack, top)->u.s.seq_len = UINT_MAX; - estack_ax(stack, top)->u.s.literal = 1; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_PLAIN; estack_ax_t = REG_STRING; next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; PO; } + OP(FILTER_OP_LOAD_STAR_GLOB_STRING): + { + struct load_op *insn = (struct load_op *) pc; + + dbg_printf("load globbing pattern %s\n", insn->data); + estack_push(stack, top, ax, bx, ax_t, bx_t); + estack_ax(stack, top)->u.s.str = insn->data; + estack_ax(stack, top)->u.s.seq_len = UINT_MAX; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_STAR_GLOB; + estack_ax_t = REG_STAR_GLOB_STRING; + next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; + PO; + } + OP(FILTER_OP_LOAD_S64): { struct load_op *insn = (struct load_op *) pc; @@ -1283,7 +1433,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, JUMP_TO(FILTER_OP_CAST_NOP); case REG_DOUBLE: JUMP_TO(FILTER_OP_CAST_DOUBLE_TO_S64); - case REG_STRING: + case REG_STRING: /* Fall-through */ + case REG_STAR_GLOB_STRING: ret = -EINVAL; goto end; default: @@ -1345,7 +1496,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, goto end; } estack_ax(stack, top)->u.s.seq_len = UINT_MAX; - estack_ax(stack, top)->u.s.literal = 0; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; dbg_printf("ref get context dynamic string %s\n", estack_ax(stack, top)->u.s.str); estack_ax_t = REG_STRING; break; @@ -1379,7 +1531,8 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, goto end; } estack_ax(stack, top)->u.s.seq_len = UINT_MAX; - estack_ax(stack, top)->u.s.literal = 0; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; estack_ax_t = REG_STRING; dbg_printf("ref get context string %s\n", estack_ax(stack, top)->u.s.str); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); diff --git a/liblttng-ust/lttng-filter-specialize.c b/liblttng-ust/lttng-filter-specialize.c index 92196dfb..09b5e45e 100644 --- a/liblttng-ust/lttng-filter-specialize.c +++ b/liblttng-ust/lttng-filter-specialize.c @@ -80,7 +80,15 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) case REG_STRING: if (vstack_bx(stack)->type == REG_UNKNOWN) break; - insn->op = FILTER_OP_EQ_STRING; + if (vstack_bx(stack)->type == REG_STAR_GLOB_STRING) + insn->op = FILTER_OP_EQ_STAR_GLOB_STRING; + else + insn->op = FILTER_OP_EQ_STRING; + break; + case REG_STAR_GLOB_STRING: + if (vstack_bx(stack)->type == REG_UNKNOWN) + break; + insn->op = FILTER_OP_EQ_STAR_GLOB_STRING; break; case REG_S64: if (vstack_bx(stack)->type == REG_UNKNOWN) @@ -124,7 +132,15 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) case REG_STRING: if (vstack_bx(stack)->type == REG_UNKNOWN) break; - insn->op = FILTER_OP_NE_STRING; + if (vstack_bx(stack)->type == REG_STAR_GLOB_STRING) + insn->op = FILTER_OP_NE_STAR_GLOB_STRING; + else + insn->op = FILTER_OP_NE_STRING; + break; + case REG_STAR_GLOB_STRING: + if (vstack_bx(stack)->type == REG_UNKNOWN) + break; + insn->op = FILTER_OP_NE_STAR_GLOB_STRING; break; case REG_S64: if (vstack_bx(stack)->type == REG_UNKNOWN) @@ -165,6 +181,10 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) ret = -EINVAL; goto end; + case REG_STAR_GLOB_STRING: + ERR("invalid register type for > binary operator\n"); + ret = -EINVAL; + goto end; case REG_STRING: if (vstack_bx(stack)->type == REG_UNKNOWN) break; @@ -209,6 +229,10 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) ret = -EINVAL; goto end; + case REG_STAR_GLOB_STRING: + ERR("invalid register type for < binary operator\n"); + ret = -EINVAL; + goto end; case REG_STRING: if (vstack_bx(stack)->type == REG_UNKNOWN) break; @@ -253,6 +277,10 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) ret = -EINVAL; goto end; + case REG_STAR_GLOB_STRING: + ERR("invalid register type for >= binary operator\n"); + ret = -EINVAL; + goto end; case REG_STRING: if (vstack_bx(stack)->type == REG_UNKNOWN) break; @@ -296,6 +324,10 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) ret = -EINVAL; goto end; + case REG_STAR_GLOB_STRING: + ERR("invalid register type for <= binary operator\n"); + ret = -EINVAL; + goto end; case REG_STRING: if (vstack_bx(stack)->type == REG_UNKNOWN) break; @@ -331,6 +363,8 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) case FILTER_OP_LT_STRING: case FILTER_OP_GE_STRING: case FILTER_OP_LE_STRING: + case FILTER_OP_EQ_STAR_GLOB_STRING: + case FILTER_OP_NE_STAR_GLOB_STRING: case FILTER_OP_EQ_S64: case FILTER_OP_NE_S64: case FILTER_OP_GT_S64: @@ -532,6 +566,19 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) break; } + case FILTER_OP_LOAD_STAR_GLOB_STRING: + { + struct load_op *insn = (struct load_op *) pc; + + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_STAR_GLOB_STRING; + next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; + break; + } + case FILTER_OP_LOAD_S64: { if (vstack_push(stack)) { @@ -568,6 +615,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) goto end; case REG_STRING: + case REG_STAR_GLOB_STRING: ERR("Cast op can only be applied to numeric or floating point registers\n"); ret = -EINVAL; goto end; diff --git a/liblttng-ust/lttng-filter-validator.c b/liblttng-ust/lttng-filter-validator.c index 75cd98a5..d24f1d80 100644 --- a/liblttng-ust/lttng-filter-validator.c +++ b/liblttng-ust/lttng-filter-validator.c @@ -31,6 +31,7 @@ #include #include "lttng-hash-helper.h" +#include "string-utils.h" /* * Number of merge points for hash table size. Hash table initialized to @@ -128,7 +129,8 @@ int merge_point_add_check(struct cds_lfht *ht, unsigned long target_pc, * (unknown), negative error value on error. */ static -int bin_op_compare_check(struct vstack *stack, const char *str) +int bin_op_compare_check(struct vstack *stack, filter_opcode_t opcode, + const char *str) { if (unlikely(!vstack_ax(stack) || !vstack_bx(stack))) goto error_empty; @@ -148,6 +150,29 @@ int bin_op_compare_check(struct vstack *stack, const char *str) goto unknown; case REG_STRING: break; + case REG_STAR_GLOB_STRING: + if (opcode != FILTER_OP_EQ && opcode != FILTER_OP_NE) { + goto error_mismatch; + } + break; + case REG_S64: + case REG_DOUBLE: + goto error_mismatch; + } + break; + case REG_STAR_GLOB_STRING: + switch (vstack_bx(stack)->type) { + default: + goto error_type; + + case REG_UNKNOWN: + goto unknown; + case REG_STRING: + if (opcode != FILTER_OP_EQ && opcode != FILTER_OP_NE) { + goto error_mismatch; + } + break; + case REG_STAR_GLOB_STRING: case REG_S64: case REG_DOUBLE: goto error_mismatch; @@ -162,6 +187,7 @@ int bin_op_compare_check(struct vstack *stack, const char *str) case REG_UNKNOWN: goto unknown; case REG_STRING: + case REG_STAR_GLOB_STRING: goto error_mismatch; case REG_S64: case REG_DOUBLE: @@ -246,6 +272,8 @@ int bytecode_validate_overflow(struct bytecode_runtime *bytecode, case FILTER_OP_LT_STRING: case FILTER_OP_GE_STRING: case FILTER_OP_LE_STRING: + case FILTER_OP_EQ_STAR_GLOB_STRING: + case FILTER_OP_NE_STAR_GLOB_STRING: case FILTER_OP_EQ_S64: case FILTER_OP_NE_S64: case FILTER_OP_GT_S64: @@ -333,6 +361,7 @@ int bytecode_validate_overflow(struct bytecode_runtime *bytecode, /* load from immediate operand */ case FILTER_OP_LOAD_STRING: + case FILTER_OP_LOAD_STAR_GLOB_STRING: { struct load_op *insn = (struct load_op *) pc; uint32_t str_len, maxlen; @@ -417,8 +446,9 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, char *pc) { int ret = 0; + const filter_opcode_t opcode = *(filter_opcode_t *) pc; - switch (*(filter_opcode_t *) pc) { + switch (opcode) { case FILTER_OP_UNKNOWN: default: { @@ -446,49 +476,49 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, case FILTER_OP_BIN_XOR: { ERR("unsupported bytecode op %u\n", - (unsigned int) *(filter_opcode_t *) pc); + (unsigned int) opcode); ret = -EINVAL; goto end; } case FILTER_OP_EQ: { - ret = bin_op_compare_check(stack, "=="); + ret = bin_op_compare_check(stack, opcode, "=="); if (ret < 0) goto end; break; } case FILTER_OP_NE: { - ret = bin_op_compare_check(stack, "!="); + ret = bin_op_compare_check(stack, opcode, "!="); if (ret < 0) goto end; break; } case FILTER_OP_GT: { - ret = bin_op_compare_check(stack, ">"); + ret = bin_op_compare_check(stack, opcode, ">"); if (ret < 0) goto end; break; } case FILTER_OP_LT: { - ret = bin_op_compare_check(stack, "<"); + ret = bin_op_compare_check(stack, opcode, "<"); if (ret < 0) goto end; break; } case FILTER_OP_GE: { - ret = bin_op_compare_check(stack, ">="); + ret = bin_op_compare_check(stack, opcode, ">="); if (ret < 0) goto end; break; } case FILTER_OP_LE: { - ret = bin_op_compare_check(stack, "<="); + ret = bin_op_compare_check(stack, opcode, "<="); if (ret < 0) goto end; break; @@ -515,6 +545,23 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, break; } + case FILTER_OP_EQ_STAR_GLOB_STRING: + case FILTER_OP_NE_STAR_GLOB_STRING: + { + if (!vstack_ax(stack) || !vstack_bx(stack)) { + ERR("Empty stack\n"); + ret = -EINVAL; + goto end; + } + if (vstack_ax(stack)->type != REG_STAR_GLOB_STRING + && vstack_bx(stack)->type != REG_STAR_GLOB_STRING) { + ERR("Unexpected register type for globbing pattern comparator\n"); + ret = -EINVAL; + goto end; + } + break; + } + case FILTER_OP_EQ_S64: case FILTER_OP_NE_S64: case FILTER_OP_GT_S64: @@ -613,6 +660,7 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, goto end; case REG_STRING: + case REG_STAR_GLOB_STRING: ERR("Unary op can only be applied to numeric or floating point registers\n"); ret = -EINVAL; goto end; @@ -726,6 +774,7 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, /* load from immediate operand */ case FILTER_OP_LOAD_STRING: + case FILTER_OP_LOAD_STAR_GLOB_STRING: { break; } @@ -757,6 +806,7 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, goto end; case REG_STRING: + case REG_STAR_GLOB_STRING: ERR("Cast op can only be applied to numeric or floating point registers\n"); ret = -EINVAL; goto end; @@ -856,7 +906,7 @@ int validate_instruction_all_contexts(struct bytecode_runtime *bytecode, node = cds_lfht_iter_get_node(&iter); if (node) { mp_node = caa_container_of(node, struct lfht_mp_node, node); - + dbg_printf("Filter: validate merge point at offset %lu\n", target_pc); if (merge_points_compare(stack, &mp_node->stack)) { @@ -940,6 +990,8 @@ int exec_insn(struct bytecode_runtime *bytecode, case FILTER_OP_LT_STRING: case FILTER_OP_GE_STRING: case FILTER_OP_LE_STRING: + case FILTER_OP_EQ_STAR_GLOB_STRING: + case FILTER_OP_NE_STAR_GLOB_STRING: case FILTER_OP_EQ_S64: case FILTER_OP_NE_S64: case FILTER_OP_GT_S64: @@ -1117,6 +1169,19 @@ int exec_insn(struct bytecode_runtime *bytecode, break; } + case FILTER_OP_LOAD_STAR_GLOB_STRING: + { + struct load_op *insn = (struct load_op *) pc; + + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_STAR_GLOB_STRING; + next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; + break; + } + case FILTER_OP_LOAD_S64: { if (vstack_push(stack)) { diff --git a/liblttng-ust/lttng-filter.h b/liblttng-ust/lttng-filter.h index 10832cea..d7105aff 100644 --- a/liblttng-ust/lttng-filter.h +++ b/liblttng-ust/lttng-filter.h @@ -83,6 +83,7 @@ enum entry_type { REG_S64, REG_DOUBLE, REG_STRING, + REG_STAR_GLOB_STRING, REG_UNKNOWN, }; @@ -141,6 +142,12 @@ int vstack_pop(struct vstack *stack) } /* Execution stack */ +enum estack_string_literal_type { + ESTACK_STRING_LITERAL_TYPE_NONE, + ESTACK_STRING_LITERAL_TYPE_PLAIN, + ESTACK_STRING_LITERAL_TYPE_STAR_GLOB, +}; + struct estack_entry { enum entry_type type; /* For dynamic typing. */ union { @@ -150,7 +157,7 @@ struct estack_entry { struct { const char *str; size_t seq_len; - int literal; /* is string literal ? */ + enum estack_string_literal_type literal_type; } s; } u; };