Filtering: add support for star-only globbing patterns
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 17 Feb 2017 09:14:40 +0000 (04:14 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 10 Mar 2017 16:28:11 +0000 (11:28 -0500)
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 <eeppeliteloop@gmail.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
include/lttng/ust-abi.h
liblttng-ust/filter-bytecode.h
liblttng-ust/lttng-filter-interpreter.c
liblttng-ust/lttng-filter-specialize.c
liblttng-ust/lttng-filter-validator.c
liblttng-ust/lttng-filter.h

index 6e8f8d7be3691a7f8d5592ab84667011b498e946..f76d2a9fa5c6b25c3d99b96a21314eb1ed86d227 100644 (file)
@@ -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,
index d5194bc25ddf02a2efc4c256c4f712686dd9eeba..b0c8f8183cf89c55a07243c8d49b17e0cc67994a 100644 (file)
@@ -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,
 };
index 0caeab6f87f66bcc838fb565dbf097575aea2e6e..afea3f151ff460e5dda5f5beef2908340ab10671 100644 (file)
@@ -27,6 +27,7 @@
 #define _LGPL_SOURCE
 #include <urcu-pointer.h>
 #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);
index 92196dfb17bcf64e9138da8ac6569b4a4906d389..09b5e45e73658a8a8a29445be1f149d6d92b50de 100644 (file)
@@ -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;
index 75cd98a5d134fe05b00ec432d8e559785e0b892e..d24f1d80bcabac8efdd2cfa73883d6035c06a2e2 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <urcu/rculfhash.h>
 #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)) {
index 10832ceab0301f5bb4c3e4dda100129600faed96..d7105aff3008fca75f1d9ac645457f7bda644867 100644 (file)
@@ -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;
 };
This page took 0.040722 seconds and 4 git commands to generate.