From: Mathieu Desnoyers Date: Thu, 22 Jun 2017 20:17:54 +0000 (-0400) Subject: Implement support for brackets in filter expressions X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=commitdiff_plain;h=661dfdd190c65bad5a044e21c1d5f9ad59144bf8 Implement support for brackets in filter expressions Extends the bytecode with new instructions. Signed-off-by: Mathieu Desnoyers Signed-off-by: Jérémie Galarneau --- diff --git a/src/lib/lttng-ctl/filter/filter-ast.h b/src/lib/lttng-ctl/filter/filter-ast.h index 73d8d44e6..067624906 100644 --- a/src/lib/lttng-ctl/filter/filter-ast.h +++ b/src/lib/lttng-ctl/filter/filter-ast.h @@ -95,6 +95,7 @@ enum ast_link_type { AST_LINK_UNKNOWN = 0, AST_LINK_DOT, AST_LINK_RARROW, + AST_LINK_BRACKET, }; struct filter_node { @@ -133,8 +134,9 @@ struct filter_node { */ struct filter_node *child; } u; - /* linked dot/arrow chain */ + /* prev: linked dot/arrow chain (postfix expression) */ struct filter_node *prev; + /* next: linked bracket chain (prefix expression) */ struct filter_node *next; } expression; struct { diff --git a/src/lib/lttng-ctl/filter/filter-bytecode.h b/src/lib/lttng-ctl/filter/filter-bytecode.h index 627d0d6f0..b7b71ad53 100644 --- a/src/lib/lttng-ctl/filter/filter-bytecode.h +++ b/src/lib/lttng-ctl/filter/filter-bytecode.h @@ -35,6 +35,12 @@ struct field_ref { uint16_t offset; } LTTNG_PACKED; +struct field_ref_index { + /* Initially, symbol offset. After link, field offset. */ + uint16_t offset; + uint64_t index; /* array index */ +} LTTNG_PACKED; + struct literal_numeric { int64_t v; } LTTNG_PACKED; @@ -163,6 +169,14 @@ enum filter_op { FILTER_OP_EQ_STAR_GLOB_STRING = 77, FILTER_OP_NE_STAR_GLOB_STRING = 78, + /* load field ref with index */ + FILTER_OP_LOAD_FIELD_REF_INDEX = 79, + FILTER_OP_LOAD_FIELD_REF_INDEX_S64 = 80, + + /* get context ref with index */ + FILTER_OP_GET_CONTEXT_REF_INDEX = 81, + FILTER_OP_GET_CONTEXT_REF_INDEX_S64 = 82, + NR_FILTER_OPS, }; diff --git a/src/lib/lttng-ctl/filter/filter-ir.h b/src/lib/lttng-ctl/filter/filter-ir.h index 10f339e6b..c07050df5 100644 --- a/src/lib/lttng-ctl/filter/filter-ir.h +++ b/src/lib/lttng-ctl/filter/filter-ir.h @@ -38,6 +38,8 @@ enum ir_data_type { IR_DATA_FLOAT, IR_DATA_FIELD_REF, IR_DATA_GET_CONTEXT_REF, + IR_DATA_FIELD_REF_INDEX, + IR_DATA_GET_CONTEXT_REF_INDEX, }; enum ir_op_type { @@ -80,6 +82,10 @@ struct ir_op_load { int64_t num; double flt; char *ref; + struct { + char *symbol; + uint64_t index; + } ref_index; } u; }; diff --git a/src/lib/lttng-ctl/filter/filter-parser.y b/src/lib/lttng-ctl/filter/filter-parser.y index 92499e075..12605cd38 100644 --- a/src/lib/lttng-ctl/filter/filter-parser.y +++ b/src/lib/lttng-ctl/filter/filter-parser.y @@ -471,6 +471,12 @@ primary_expression postfix_expression : primary_expression { $$ = $1; } + | postfix_expression LSBRAC unary_expression RSBRAC + { + $$ = $1; + $$->u.expression.pre_op = AST_LINK_BRACKET; + $$->u.expression.next = $3; + } | postfix_expression DOT IDENTIFIER { $$ = make_node(parser_ctx, NODE_EXPRESSION); diff --git a/src/lib/lttng-ctl/filter/filter-visitor-generate-bytecode.c b/src/lib/lttng-ctl/filter/filter-visitor-generate-bytecode.c index d0cc49556..74cef91dc 100644 --- a/src/lib/lttng-ctl/filter/filter-visitor-generate-bytecode.c +++ b/src/lib/lttng-ctl/filter/filter-visitor-generate-bytecode.c @@ -252,7 +252,7 @@ int visit_node_load(struct filter_parser_ctx *ctx, struct ir_op *node) insn = calloc(insn_len, 1); if (!insn) return -ENOMEM; - switch(node->data_type) { + switch (node->data_type) { case IR_DATA_FIELD_REF: insn->op = FILTER_OP_LOAD_FIELD_REF; break; @@ -289,6 +289,57 @@ int visit_node_load(struct filter_parser_ctx *ctx, struct ir_op *node) free(insn); return ret; } + case IR_DATA_FIELD_REF_INDEX: /* fall-through */ + case IR_DATA_GET_CONTEXT_REF_INDEX: + { + struct load_op *insn; + uint32_t insn_len = sizeof(struct load_op) + + sizeof(struct field_ref_index); + struct field_ref_index ref_index_offset; + uint32_t reloc_offset_u32; + uint16_t reloc_offset; + + insn = calloc(insn_len, 1); + if (!insn) + return -ENOMEM; + switch (node->data_type) { + case IR_DATA_FIELD_REF_INDEX: + insn->op = FILTER_OP_LOAD_FIELD_REF_INDEX; + break; + case IR_DATA_GET_CONTEXT_REF_INDEX: + insn->op = FILTER_OP_GET_CONTEXT_REF_INDEX; + break; + default: + free(insn); + return -EINVAL; + } + ref_index_offset.offset = (uint16_t) -1U; + ref_index_offset.index = node->u.load.u.ref_index.index; + memcpy(insn->data, &ref_index_offset, sizeof(ref_index_offset)); + /* reloc_offset points to struct load_op */ + reloc_offset_u32 = bytecode_get_len(&ctx->bytecode->b); + if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) { + free(insn); + return -EINVAL; + } + reloc_offset = (uint16_t) reloc_offset_u32; + ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len); + if (ret) { + free(insn); + return ret; + } + /* append reloc */ + ret = bytecode_push(&ctx->bytecode_reloc, &reloc_offset, + 1, sizeof(reloc_offset)); + if (ret) { + free(insn); + return ret; + } + ret = bytecode_push(&ctx->bytecode_reloc, node->u.load.u.ref_index.symbol, + 1, strlen(node->u.load.u.ref_index.symbol) + 1); + free(insn); + return ret; + } } } @@ -423,12 +474,16 @@ int visit_node_logical(struct filter_parser_ctx *ctx, struct ir_op *node) 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_GET_CONTEXT_REF + || node->u.binary.left->data_type == IR_DATA_FIELD_REF_INDEX + || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF_INDEX) || 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_GET_CONTEXT_REF + || node->u.binary.left->data_type == IR_DATA_FIELD_REF_INDEX + || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF_INDEX) { cast_insn.op = FILTER_OP_CAST_TO_S64; } else { cast_insn.op = FILTER_OP_CAST_DOUBLE_TO_S64; @@ -462,12 +517,16 @@ int visit_node_logical(struct filter_parser_ctx *ctx, struct ir_op *node) 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_GET_CONTEXT_REF + || node->u.binary.right->data_type == IR_DATA_FIELD_REF_INDEX + || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF_INDEX) || 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_GET_CONTEXT_REF + || node->u.binary.right->data_type == IR_DATA_FIELD_REF_INDEX + || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF_INDEX) { cast_insn.op = FILTER_OP_CAST_TO_S64; } else { cast_insn.op = FILTER_OP_CAST_DOUBLE_TO_S64; diff --git a/src/lib/lttng-ctl/filter/filter-visitor-generate-ir.c b/src/lib/lttng-ctl/filter/filter-visitor-generate-ir.c index e3dc1aab9..85aadcae6 100644 --- a/src/lib/lttng-ctl/filter/filter-visitor-generate-ir.c +++ b/src/lib/lttng-ctl/filter/filter-visitor-generate-ir.c @@ -140,7 +140,8 @@ struct ir_op *make_op_load_float(double v, enum ir_side side) } static -struct ir_op *make_op_load_field_ref(char *string, enum ir_side side) +struct ir_op *make_op_load_field_ref(char *string, + enum ir_side side) { struct ir_op *op; @@ -153,14 +154,61 @@ struct ir_op *make_op_load_field_ref(char *string, enum ir_side side) op->side = side; op->u.load.u.ref = strdup(string); if (!op->u.load.u.ref) { - free(op); + goto error; + } + return op; + +error: + free(op); + return NULL; +} + +static +struct ir_op *make_op_load_field_ref_index(char *string, + struct filter_node *next, + 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_FIELD_REF_INDEX; + op->signedness = IR_SIGN_DYN; + op->side = side; + op->u.load.u.ref_index.symbol = strdup(string); + if (!op->u.load.u.ref_index.symbol) { + goto error; + } + /* Only positive integer literals accepted as index. */ + if (next->type == NODE_UNARY_OP) { + fprintf(stderr, "[error] Unexpected unary operator as index\n"); + goto error; + } + if (next->type != NODE_EXPRESSION) { + fprintf(stderr, "[error] Expecting expression as index\n"); + goto error; + } + if (next->u.expression.type != AST_EXP_CONSTANT) { + fprintf(stderr, "[error] Expecting constant index\n"); + goto error; + } + if (next->u.expression.u.constant < 0) { + fprintf(stderr, "[error] Expecting positive constant index\n"); + goto error; } + op->u.load.u.ref_index.index = next->u.expression.u.constant; return op; + +error: + free(op); + return NULL; } static -struct ir_op *make_op_load_get_context_ref(char *string, enum ir_side side) +struct ir_op *make_op_load_get_context_ref(char *string, + enum ir_side side) { struct ir_op *op; @@ -173,10 +221,56 @@ struct ir_op *make_op_load_get_context_ref(char *string, enum ir_side side) op->side = side; op->u.load.u.ref = strdup(string); if (!op->u.load.u.ref) { - free(op); + goto error; + } + return op; + +error: + free(op); + return NULL; +} + +static +struct ir_op *make_op_load_get_context_ref_index(char *string, + struct filter_node *next, + 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_GET_CONTEXT_REF_INDEX; + op->signedness = IR_SIGN_DYN; + op->side = side; + op->u.load.u.ref_index.symbol = strdup(string); + if (!op->u.load.u.ref_index.symbol) { + goto error; + } + /* Only positive integer literals accepted as offset. */ + if (next->type == NODE_UNARY_OP) { + fprintf(stderr, "[error] Unexpected unary operator as index\n"); + goto error; + } + if (next->type != NODE_EXPRESSION) { + fprintf(stderr, "[error] Expecting expression as index\n"); + goto error; } + if (next->u.expression.type != AST_EXP_CONSTANT) { + fprintf(stderr, "[error] Expecting constant index\n"); + goto error; + } + if (next->u.expression.u.constant < 0) { + fprintf(stderr, "[error] Expecting positive constant index\n"); + goto error; + } + op->u.load.u.ref_index.index = next->u.expression.u.constant; return op; + +error: + free(op); + return NULL; } static @@ -390,6 +484,10 @@ void filter_free_ir_recursive(struct ir_op *op) case IR_DATA_GET_CONTEXT_REF: free(op->u.load.u.ref); break; + case IR_DATA_FIELD_REF_INDEX: /* fall-through */ + case IR_DATA_GET_CONTEXT_REF_INDEX: + free(op->u.load.u.ref_index.symbol); + break; default: break; } @@ -428,12 +526,18 @@ struct ir_op *make_expression(struct filter_parser_ctx *ctx, return make_op_load_float(node->u.expression.u.float_constant, side); case AST_EXP_IDENTIFIER: - if (node->u.expression.pre_op != AST_LINK_UNKNOWN) { + switch (node->u.expression.pre_op) { + case AST_LINK_UNKNOWN: + return make_op_load_field_ref(node->u.expression.u.identifier, + side); + case AST_LINK_BRACKET: + return make_op_load_field_ref_index(node->u.expression.u.identifier, + node->u.expression.next, + side); + default: fprintf(stderr, "[error] %s: dotted and dereferenced identifiers not supported\n", __func__); return NULL; } - return make_op_load_field_ref(node->u.expression.u.identifier, - side); case AST_EXP_GLOBAL_IDENTIFIER: { const char *name; @@ -459,8 +563,19 @@ struct ir_op *make_expression(struct filter_parser_ctx *ctx, fprintf(stderr, "[error] %s: Expecting a context name, e.g. \'$ctx.name\'.\n", __func__); return NULL; } - return make_op_load_get_context_ref(node->u.expression.u.identifier, + switch (node->u.expression.pre_op) { + case AST_LINK_UNKNOWN: + return make_op_load_get_context_ref(node->u.expression.u.identifier, side); + case AST_LINK_BRACKET: + return make_op_load_get_context_ref_index(node->u.expression.u.identifier, + node->u.expression.next, + side); + default: + fprintf(stderr, "[error] %s: dotted and dereferenced identifiers not supported\n", __func__); + return NULL; + } + } case AST_EXP_NESTED: return generate_ir_recursive(ctx, node->u.expression.u.child, diff --git a/src/lib/lttng-ctl/filter/filter-visitor-xml.c b/src/lib/lttng-ctl/filter/filter-visitor-xml.c index 24d618ac9..c293ad15e 100644 --- a/src/lib/lttng-ctl/filter/filter-visitor-xml.c +++ b/src/lib/lttng-ctl/filter/filter-visitor-xml.c @@ -49,6 +49,8 @@ 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; @@ -80,33 +82,18 @@ int recursive_visit_print_expression(struct filter_node *node, node->u.expression.type == AST_EXP_IDENTIFIER ? "identifier" : "global_identifier", node->u.expression.u.identifier); - while (node->u.expression.next) { + iter_node = node->u.expression.next; + while (iter_node) { print_tabs(stream, indent); - fprintf(stream, "u.expression.pre_op) { - case AST_LINK_UNKNOWN: - default: - fprintf(stderr, "[error] %s: unknown link\n", __func__); - return -EINVAL; - case AST_LINK_DOT: - fprintf(stream, "."); - break; - case AST_LINK_RARROW: - fprintf(stream, "->"); - break; - } - fprintf(stream, "\"/>\n"); - - node = node->u.expression.next; - if (node->type != NODE_EXPRESSION || - node->u.expression.type != AST_EXP_IDENTIFIER) { - fprintf(stderr, "[error] %s: expecting identifier before link\n", __func__); + fprintf(stream, "\n"); + if (recursive_visit_print_expression(iter_node, + stream, indent + 1)) { return -EINVAL; } - print_tabs(stream, indent); - fprintf(stream, "\n", - node->u.expression.u.identifier); + fprintf(stream, "\n"); + iter_node = iter_node->u.expression.next; + } break; case AST_EXP_NESTED: